lots of improvements
This commit is contained in:
parent
2082001ff8
commit
417657f138
31 changed files with 514 additions and 476 deletions
|
@ -1,12 +1,10 @@
|
|||
<Component>
|
||||
<section class="grid-banner">
|
||||
<div class="notification">
|
||||
<div class="container">
|
||||
Snowpack 3.0 is out now!
|
||||
<a href="/posts/2021-01-13-snowpack-3-0">
|
||||
Read the announcement post →
|
||||
</a>
|
||||
</div>
|
||||
<section class="grid-banner">
|
||||
<div class="notification">
|
||||
<div class="container">
|
||||
Snowpack 3.0 is out now!
|
||||
<a href="/posts/2021-01-13-snowpack-3-0">
|
||||
Read the announcement post →
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</Component>
|
||||
</div>
|
||||
</section>
|
|
@ -1,5 +1,4 @@
|
|||
<Component>
|
||||
<div class="hero">
|
||||
<div class="hero">
|
||||
<div class="section">
|
||||
<h1 class="header-snowpack">Snowpack</h1>
|
||||
<p class="header-snowpack-subtitle">The faster frontend build tool.</p>
|
||||
|
@ -7,11 +6,15 @@
|
|||
<div class="hero-cta">
|
||||
<a href="/tutorials/quick-start" class="button button-primary">Get started</a>
|
||||
<div style="margin: 0.5rem"></div>
|
||||
<button id="copy-button" class="copy-button hidden-mobile" data-clipboard-text="npm install snowpack">
|
||||
<button id="copy-button" class="copy-button hidden-mobile" data-clipboard-text="npm install snowpack">
|
||||
<span class="faded" style="margin-right: 0.75rem;">$</span>
|
||||
<span id="copy-button-text">npm install snowpack</span>
|
||||
<svg style="height: 22px;width: 22px;margin: -0.1rem -0.1rem 0 0.75rem;" aria-hidden="true" focusable="false" data-prefix="far" data-icon="clone" class="svg-inline--fa fa-clone fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512">
|
||||
<path fill="currentColor" d="M464 0H144c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h48c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48zM362 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h42v224c0 26.51 21.49 48 48 48h224v42a6 6 0 0 1-6 6zm96-96H150a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1-6 6z"></path>
|
||||
<svg style="height: 22px;width: 22px;margin: -0.1rem -0.1rem 0 0.75rem;" aria-hidden="true" focusable="false"
|
||||
data-prefix="far" data-icon="clone" class="svg-inline--fa fa-clone fa-w-16" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512">
|
||||
<path fill="currentColor"
|
||||
d="M464 0H144c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h48c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48zM362 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h42v224c0 26.51 21.49 48 48 48h224v42a6 6 0 0 1-6 6zm96-96H150a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1-6 6z">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<script type="module">
|
||||
|
@ -19,10 +22,10 @@
|
|||
const clippy = new Clipboard('.copy-button');
|
||||
const copyText = document.getElementById('copy-button').innerHTML;
|
||||
clippy.on('success', function (e) {
|
||||
document.getElementById('copy-button').style.minWidth = document.getElementById('copy-button').offsetWidth;
|
||||
document.getElementById('copy-button').style.minWidth = document.getElementById('copy-button').offsetWidth;
|
||||
console.info('Trigger:', e);
|
||||
document.getElementById('copy-button').innerHTML = '<span>copied to clipboard!</span>';
|
||||
document.getElementById('copy-button').addEventListener("mouseleave", function( event ) {
|
||||
document.getElementById('copy-button').addEventListener("mouseleave", function (event) {
|
||||
document.getElementById('copy-button').innerHTML = copyText;
|
||||
}, false);
|
||||
|
||||
|
@ -39,9 +42,9 @@
|
|||
<div class="hero-cta">
|
||||
<!-- Place this tag where you want the button to render. -->
|
||||
<div class="hidden-mobile" style="text-align: center; height: 36px;">
|
||||
<a class="github-button" href="https://github.com/snowpackjs/snowpack" data-icon="octicon-star" data-size="large" data-show-count="true" aria-label="Star snowpackjs/snowpack on GitHub">Star</a >
|
||||
<a class="github-button" href="https://github.com/snowpackjs/snowpack" data-icon="octicon-star"
|
||||
data-size="large" data-show-count="true" aria-label="Star snowpackjs/snowpack on GitHub">Star</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Component>
|
||||
</div>
|
|
@ -1,4 +1,3 @@
|
|||
<Component>
|
||||
<nav class="snow-toc">
|
||||
<ol class="snow-toc-contents">
|
||||
<li class="snow-toc-section">
|
||||
|
@ -83,4 +82,3 @@
|
|||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</Component>
|
||||
|
|
|
@ -1,21 +1,27 @@
|
|||
<Component>
|
||||
<nav class="snow-nav">
|
||||
<button id="toc-drawer-button" class="snow-nav-mobile-open" type="button" aria-expanded="false" aria-controls="nav-primary">
|
||||
<button id="toc-drawer-button" class="snow-nav-mobile-open" type="button" aria-expanded="false"
|
||||
aria-controls="nav-primary">
|
||||
<svg focusable="false" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 448 512">
|
||||
<title>Toggle mobile menu</title>
|
||||
<path d="M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"></path>
|
||||
<path
|
||||
d="M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<a class="snow-nav-logo snow-logo" href="/">
|
||||
<svg class="snow-logo-icon" viewbox="0 0 640 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<svg class="snow-logo-icon" viewbox="0 0 640 512" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g transform="translate(-1.000000, 0.000000)" fill-rule="nonzero">
|
||||
<path d="M635.92,462.7 L347.92,14.7 C342.03,5.54 331.89,0 321,0 C310.11,0 299.97,5.54 294.08,14.7 L6.08,462.7 C-0.250773249,472.547007 -0.699487627,485.064987 4.91,495.34 C10.522069,505.612419 21.2945349,512 33,512 L609,512 C620.71,512 631.48,505.61 637.09,495.33 C642.699457,485.058495 642.250708,472.543372 635.92,462.7 Z M321,91.18 L406.39,224 L321,224 L257,288 L218.94,249.94 L321,91.18 Z" id="Shape"></path>
|
||||
<path
|
||||
d="M635.92,462.7 L347.92,14.7 C342.03,5.54 331.89,0 321,0 C310.11,0 299.97,5.54 294.08,14.7 L6.08,462.7 C-0.250773249,472.547007 -0.699487627,485.064987 4.91,495.34 C10.522069,505.612419 21.2945349,512 33,512 L609,512 C620.71,512 631.48,505.61 637.09,495.33 C642.699457,485.058495 642.250708,472.543372 635.92,462.7 Z M321,91.18 L406.39,224 L321,224 L257,288 L218.94,249.94 L321,91.18 Z"
|
||||
id="Shape"></path>
|
||||
</g>
|
||||
</svg>
|
||||
<span class="snow-logo-type">Snowpack</span>
|
||||
</a>
|
||||
<div class="search-form">
|
||||
<input type="text" name="search" placeholder="Search documentation..." class="search-form-input" id="search-form-input">
|
||||
<input type="text" name="search" placeholder="Search documentation..." class="search-form-input"
|
||||
id="search-form-input">
|
||||
<span class="search-form-hint">
|
||||
<span class="sr-only">Press </span>
|
||||
<kbd class="font-sans"><abbr title="Command" style="text-decoration: none;">⌘</abbr></kbd>
|
||||
|
@ -29,64 +35,75 @@
|
|||
{`v${props.version}`}
|
||||
</a>
|
||||
<a href="https://github.com/snowpackjs/snowpack" target="_blank" class="snow-nav-link snow-nav-link__desktop">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="github" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 496 512">
|
||||
<path fill="currentColor" d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path>
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="github" class="snow-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewbox="0 0 496 512">
|
||||
<path fill="currentColor"
|
||||
d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z">
|
||||
</path>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://twitter.com/snowpackjs" target="_blank" class="snow-nav-link snow-nav-link__desktop">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="twitter" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512">
|
||||
<path fill="currentColor" d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path>
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="twitter" class="snow-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512">
|
||||
<path fill="currentColor"
|
||||
d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z">
|
||||
</path>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://discord.gg/snowpack" target="_blank" class="snow-nav-link snow-nav-link__desktop">
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="discord" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 210 240"><path d="M84.79 90.45c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57.11-6.91-5.09-12.57-11.55-12.57zm41.32 0c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57s-5.09-12.57-11.55-12.57z"/><path fill="currentColor" d="M185.4 0H24.6C11.04 0 0 11.04 0 24.72v162.24c0 13.68 11.04 24.72 24.6 24.72h136.08l-6.36-22.2 15.36 14.28 14.52 13.44L210 240V24.72C210 11.04 198.96 0 185.4 0zm-46.32 156.72s-4.32-5.16-7.92-9.72c15.72-4.44 21.72-14.28 21.72-14.28-4.92 3.24-9.6 5.52-13.8 7.08-6 2.52-11.76 4.2-17.4 5.16-11.52 2.16-22.08 1.56-31.08-.12-6.84-1.32-12.72-3.24-17.64-5.16-2.76-1.08-5.76-2.4-8.76-4.08-.36-.24-.72-.36-1.08-.6-.24-.12-.36-.24-.48-.36-2.16-1.2-3.36-2.04-3.36-2.04s5.76 9.6 21 14.16c-3.6 4.56-8.04 9.96-8.04 9.96-26.52-.84-36.6-18.24-36.6-18.24 0-38.64 17.28-69.96 17.28-69.96 17.28-12.96 33.72-12.6 33.72-12.6l1.2 1.44c-21.6 6.24-31.56 15.72-31.56 15.72s2.64-1.44 7.08-3.48c12.84-5.64 23.04-7.2 27.24-7.56.72-.12 1.32-.24 2.04-.24 7.32-.96 15.6-1.2 24.24-.24 11.4 1.32 23.64 4.68 36.12 11.52 0 0-9.48-9-29.88-15.24l1.68-1.92s16.44-.36 33.72 12.6c0 0 17.28 31.32 17.28 69.96 0 0-10.2 17.4-36.72 18.24z"/></svg>
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="discord" class="snow-icon" role="img"
|
||||
xmlns="http://www.w3.org/2000/svg" viewbox="0 0 210 240">
|
||||
<path
|
||||
d="M84.79 90.45c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57.11-6.91-5.09-12.57-11.55-12.57zm41.32 0c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57s-5.09-12.57-11.55-12.57z" />
|
||||
<path fill="currentColor"
|
||||
d="M185.4 0H24.6C11.04 0 0 11.04 0 24.72v162.24c0 13.68 11.04 24.72 24.6 24.72h136.08l-6.36-22.2 15.36 14.28 14.52 13.44L210 240V24.72C210 11.04 198.96 0 185.4 0zm-46.32 156.72s-4.32-5.16-7.92-9.72c15.72-4.44 21.72-14.28 21.72-14.28-4.92 3.24-9.6 5.52-13.8 7.08-6 2.52-11.76 4.2-17.4 5.16-11.52 2.16-22.08 1.56-31.08-.12-6.84-1.32-12.72-3.24-17.64-5.16-2.76-1.08-5.76-2.4-8.76-4.08-.36-.24-.72-.36-1.08-.6-.24-.12-.36-.24-.48-.36-2.16-1.2-3.36-2.04-3.36-2.04s5.76 9.6 21 14.16c-3.6 4.56-8.04 9.96-8.04 9.96-26.52-.84-36.6-18.24-36.6-18.24 0-38.64 17.28-69.96 17.28-69.96 17.28-12.96 33.72-12.6 33.72-12.6l1.2 1.44c-21.6 6.24-31.56 15.72-31.56 15.72s2.64-1.44 7.08-3.48c12.84-5.64 23.04-7.2 27.24-7.56.72-.12 1.32-.24 2.04-.24 7.32-.96 15.6-1.2 24.24-.24 11.4 1.32 23.64 4.68 36.12 11.52 0 0-9.48-9-29.88-15.24l1.68-1.92s16.44-.36 33.72 12.6c0 0 17.28 31.32 17.28 69.96 0 0-10.2 17.4-36.72 18.24z" />
|
||||
</svg>
|
||||
</a>
|
||||
</nav>
|
||||
<script>
|
||||
function handleMobileNav(evt) {
|
||||
evt.preventDefault();
|
||||
/*If hidden-mobile class is enabled that means we are on desktop do overflow normal but we
|
||||
if we are at mobile fixed body position, so that its not scrollable(which currently causing bug) and navbar handling its
|
||||
owns scroll. Case to consider there are chance use can open navbar using toggle button and user when click on any link
|
||||
body postion should be unset
|
||||
*/
|
||||
document.body.classList.toggle('is-nav-open');
|
||||
const isOpen = document.body.classList.contains('is-nav-open');
|
||||
if (isOpen) {
|
||||
evt.target.setAttribute('aria-expanded', 'true');
|
||||
} else {
|
||||
evt.target.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
<script>
|
||||
function handleMobileNav(evt) {
|
||||
evt.preventDefault();
|
||||
/*If hidden-mobile class is enabled that means we are on desktop do overflow normal but we
|
||||
if we are at mobile fixed body position, so that its not scrollable(which currently causing bug) and navbar handling its
|
||||
owns scroll. Case to consider there are chance use can open navbar using toggle button and user when click on any link
|
||||
body postion should be unset
|
||||
*/
|
||||
document.body.classList.toggle('is-nav-open');
|
||||
const isOpen = document.body.classList.contains('is-nav-open');
|
||||
if (isOpen) {
|
||||
evt.target.setAttribute('aria-expanded', 'true');
|
||||
} else {
|
||||
evt.target.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
}
|
||||
|
||||
const mobileNavBtn = document.getElementById('toc-drawer-button');
|
||||
mobileNavBtn.addEventListener('click', handleMobileNav);
|
||||
mobileNavBtn.addEventListener('touchend', handleMobileNav);
|
||||
if (window.location.pathname.startsWith('/posts')) {
|
||||
mobileNavBtn.style.display = 'none';
|
||||
}
|
||||
const mobileNavBtn = document.getElementById('toc-drawer-button');
|
||||
mobileNavBtn.addEventListener('click', handleMobileNav);
|
||||
mobileNavBtn.addEventListener('touchend', handleMobileNav);
|
||||
if (window.location.pathname.startsWith('/posts')) {
|
||||
mobileNavBtn.style.display = 'none';
|
||||
}
|
||||
|
||||
const searchFormInputEl = document.getElementById('search-form-input');
|
||||
searchFormInputEl.addEventListener('keyup', () => {
|
||||
const searchFormInputEl = document.getElementById('search-form-input');
|
||||
searchFormInputEl.addEventListener('keyup', () => {
|
||||
const gridTocEl = document.querySelector('#nav-primary');
|
||||
if (searchFormInputEl.value) {
|
||||
gridTocEl.classList.add('is-mobile-hidden');
|
||||
} else {
|
||||
gridTocEl.classList.remove('is-mobile-hidden');
|
||||
}
|
||||
});
|
||||
if (searchFormInputEl.value) {
|
||||
gridTocEl.classList.add('is-mobile-hidden');
|
||||
} else {
|
||||
gridTocEl.classList.remove('is-mobile-hidden');
|
||||
}
|
||||
});
|
||||
|
||||
document.onkeydown = function (e) {
|
||||
if ((e.ctrlKey || e.metaKey) && e.which == 75) {
|
||||
e.preventDefault();
|
||||
searchFormInputEl.focus();
|
||||
}
|
||||
};
|
||||
document.onkeydown = function (e) {
|
||||
if ((e.ctrlKey || e.metaKey) && e.which == 75) {
|
||||
e.preventDefault();
|
||||
searchFormInputEl.focus();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script type="module" defer>
|
||||
import docsearch from 'docsearch.js/dist/cdn/docsearch.min.js';
|
||||
docsearch({
|
||||
apiKey: '562139304880b94536fc53f5d65c5c19', indexName: 'snowpack', inputSelector: '.search-form-input', debug: true // Set debug to true if you want to inspect the dropdown
|
||||
});
|
||||
</script>
|
||||
</Component>
|
||||
</script>
|
|
@ -1,19 +1,21 @@
|
|||
<Component>
|
||||
<script type="module" defer src="/js/index.js"></script>
|
||||
<aside class="snow-toc snow-toc__subnav snow-view-subnav">
|
||||
<h2 class="content-title">
|
||||
{props.title}
|
||||
</h2>
|
||||
<script type="module" defer src="/js/index.js"></script>
|
||||
<aside class="snow-toc snow-toc__subnav snow-view-subnav">
|
||||
<h2 class="content-title">
|
||||
{props.title}
|
||||
</h2>
|
||||
|
||||
{props.headers.length > 0 && <div>
|
||||
<h4 class="snow-toc-section-header">On this page</h4>
|
||||
<nav class="toc">
|
||||
<ol>
|
||||
{props.headings.map((heading) => {
|
||||
return <li><a href={heading.url}>{heading.text}</a></li>
|
||||
{props.headers.map((heading) => {
|
||||
return <li><a href={"#" + heading.slug}>{heading.text}</a></li>
|
||||
})}
|
||||
</ol>
|
||||
</nav>
|
||||
<hr />
|
||||
<h4 class="snow-toc-section-header">Suggest a change</h4>
|
||||
<a href="https://github.com/snowpackjs/snowpack/blob/main/www/{props.inputPath}">Edit this page on GitHub</a>
|
||||
</aside>
|
||||
</Component>
|
||||
</div>}
|
||||
|
||||
<h4 class="snow-toc-section-header">Suggest a change</h4>
|
||||
<a href="https://github.com/snowpackjs/snowpack/blob/main/www/{props.inputPath}">Edit this page on GitHub</a>
|
||||
</aside>
|
|
@ -1,56 +1,56 @@
|
|||
<script hmx="setup">
|
||||
<script astro>
|
||||
import Banner from '../components/Banner.hmx';
|
||||
import Nav from '../components/Nav.hmx';
|
||||
export function setup() {
|
||||
export function setup({ context }) {
|
||||
return {
|
||||
title: 'Snowpack',
|
||||
description: 'Snowpack is a lightning-fast frontend build tool, designed for the modern web.',
|
||||
props: {
|
||||
version: '3.0.13',
|
||||
context: {
|
||||
title: 'Snowpack',
|
||||
description: 'Snowpack is a lightning-fast frontend build tool, designed for the modern web.',
|
||||
currentSnowpackVersion: '3.0.13',
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<head>
|
||||
<slot:head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png"/>
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/favicon/site.webmanifest" />
|
||||
|
||||
<!-- Primary Meta Tags -->
|
||||
<title>{title}</title>
|
||||
<meta name="title" content={title} />
|
||||
<meta name="description" content="{description}" />
|
||||
<title>{context.title}</title>
|
||||
<meta name="title" content={context.title} />
|
||||
<meta name="description" content="{context.description}" />
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website"/>
|
||||
<meta property="og:url" content="https://www.snowpack.dev{props.permalink}"/>
|
||||
<meta property="og:title" content={title}/>
|
||||
<meta property="og:description" content={description}/>
|
||||
<meta property="og:image" content="https://www.snowpack.dev/img/social-2.jpg"/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={context.permalink}/>
|
||||
<meta property="og:title" content={context.title} />
|
||||
<meta property="og:description" content={context.description} />
|
||||
<meta property="og:image" content="https://www.snowpack.dev/img/social-2.jpg" />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image"/>
|
||||
<meta property="twitter:url" content="https://www.snowpack.dev{props.permalink}"/>
|
||||
<meta property="twitter:title" content={title}/>
|
||||
<meta property="twitter:description" content={description}/>
|
||||
<meta property="twitter:image" content="https://www.snowpack.dev/img/social-2.jpg"/>
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content={context.permalink}/>
|
||||
<meta property="twitter:title" content={context.title} />
|
||||
<meta property="twitter:description" content={context.description} />
|
||||
<meta property="twitter:image" content="https://www.snowpack.dev/img/social-2.jpg" />
|
||||
|
||||
<!-- Global Stylesheets -->
|
||||
<link rel="stylesheet" href="/css/app.css" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Overpass:wght@400;700;900&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Overpass:wght@400;700;900&display=swap" rel="stylesheet" />
|
||||
|
||||
<!-- Note: You can then add additional, custom things here as well. -->
|
||||
<!-- if no slot given, assume add to bottom -->
|
||||
<slot></slot>
|
||||
</head>
|
||||
</slot:head>
|
||||
|
||||
<body class="base 2">
|
||||
<slot:body>
|
||||
<Banner></Banner>
|
||||
<Nav version={props.version} />
|
||||
<Nav version={context.currentSnowpackVersion} />
|
||||
|
||||
<!-- if no slot given, assume add to bottom -->
|
||||
<slot></slot>
|
||||
|
@ -65,4 +65,4 @@
|
|||
gtag('js', new Date());
|
||||
gtag('config', 'UA-130280175-9', { page_path: location.pathname === '/' ? (location.pathname + location.hash) : (location.pathname) });
|
||||
</script>
|
||||
</body>
|
||||
</slot:body>
|
|
@ -1,12 +1,14 @@
|
|||
<script hmx="setup">
|
||||
<script astro>
|
||||
import Menu from '../components/Menu.hmx';
|
||||
import Subnav from '../components/Subnav.hmx';
|
||||
export function setup() {
|
||||
return {layout: 'layouts/base.hmx', props: {}};
|
||||
|
||||
export const layout = 'layouts/base.hmx';
|
||||
export function setup({ context }) {
|
||||
return {};
|
||||
}
|
||||
</script>
|
||||
|
||||
<head>
|
||||
<slot:head>
|
||||
<style>
|
||||
.cover-wrapper {
|
||||
width: 100%;
|
||||
|
@ -47,13 +49,13 @@
|
|||
</style>
|
||||
|
||||
<slot></slot>
|
||||
</head>
|
||||
</slot:head>
|
||||
|
||||
<body>
|
||||
<slot:body>
|
||||
|
||||
<div class="cover-wrapper">
|
||||
<img class="cover-blur" src={props.cover} alt=""/>
|
||||
<img class="cover" src={props.cover} alt=""/>
|
||||
<img class="cover-blur" src={context.cover} alt=""/>
|
||||
<img class="cover" src={context.cover} alt=""/>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
@ -66,7 +68,7 @@
|
|||
<article class="snow-view-main">
|
||||
<div class="content">
|
||||
<h2 class="content-title">
|
||||
{title}
|
||||
{context.title}
|
||||
</h2>
|
||||
<div class="content-layout">
|
||||
<div class="content-body">
|
||||
|
@ -76,7 +78,7 @@
|
|||
</div>
|
||||
</article>
|
||||
|
||||
<Subnav title={title} />
|
||||
<Subnav title={context.title} headers={context.content.headers} />
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</slot:body>
|
|
@ -1,33 +1,22 @@
|
|||
<script hmx="setup">
|
||||
<script astro>
|
||||
import Subnav from '../components/Subnav.hmx';
|
||||
import Menu from '../components/Menu.hmx';
|
||||
import markdownToAst from "mdast-util-from-markdown";
|
||||
import markdownTableOfContents from "mdast-util-toc";
|
||||
|
||||
export function setup({content}) {
|
||||
const mdAst = markdownToAst(content.source);
|
||||
// This is super gross, and just me trying to get an existing table of contents generator to work
|
||||
// we can either do this internally as helpful sugar, or build a simpler one as a plugin
|
||||
const headingsAst = markdownTableOfContents(mdAst);
|
||||
const headings = headingsAst.map ? headingsAst.map.children.map(ch => {
|
||||
return {depth: 1, url: ch.children[0].children[0].url, text: ch.children[0].children[0].children[0].value};
|
||||
}) : [];
|
||||
|
||||
return {
|
||||
layout: 'layouts/base.hmx',
|
||||
props: {
|
||||
headings,
|
||||
}
|
||||
export const layout = 'layouts/base.hmx';
|
||||
export function setup({ context }) {
|
||||
return {
|
||||
context: {
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<head>
|
||||
<slot:head>
|
||||
|
||||
<slot></slot>
|
||||
</head>
|
||||
</slot:head>
|
||||
|
||||
<body>
|
||||
<slot:body>
|
||||
<div class="container">
|
||||
<section class="snow-view__docs has-subnav">
|
||||
|
||||
|
@ -35,12 +24,12 @@
|
|||
<Menu />
|
||||
</aside>
|
||||
|
||||
<Subnav title={title} headings={props.headings} />
|
||||
<Subnav title={context.title} headers={context.content.headers} />
|
||||
|
||||
<article class="snow-view-main">
|
||||
<div class="content">
|
||||
<h2 class="content-title">
|
||||
{title}
|
||||
{context.title}
|
||||
</h2>
|
||||
<div class="content-layout">
|
||||
<div class="content-body">
|
||||
|
@ -52,4 +41,4 @@
|
|||
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</slot:body>
|
|
@ -1,20 +1,18 @@
|
|||
<script hmx="setup">
|
||||
<script astro>
|
||||
import Menu from '../components/Menu.hmx';
|
||||
export function setup() {
|
||||
return {
|
||||
layout: 'layouts/base.hmx',
|
||||
props: {}
|
||||
};
|
||||
export const layout = 'layouts/base.hmx';
|
||||
export function setup({ context }) {
|
||||
return {};
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<head>
|
||||
<slot:head>
|
||||
<!-- hi -->
|
||||
<slot></slot>
|
||||
</head>
|
||||
</slot:head>
|
||||
|
||||
<body class="base 2">
|
||||
<slot:body>
|
||||
<div class="container">
|
||||
<section class="snow-view__docs is-full">
|
||||
|
||||
|
@ -28,4 +26,4 @@
|
|||
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</slot:body>
|
|
@ -1,11 +1,12 @@
|
|||
<script hmx="setup">
|
||||
<script astro>
|
||||
import {format as formatDate, parseISO} from 'date-fns';
|
||||
export function setup() {
|
||||
return { layout: 'layouts/base.hmx', props: {} };
|
||||
export const layout = 'layouts/base.hmx';
|
||||
export function setup({ context }) {
|
||||
return {};
|
||||
}
|
||||
</script>
|
||||
|
||||
<head>
|
||||
<slot:head>
|
||||
<link rel="stylesheet" href="/css/legacy-post.css" />
|
||||
<style>
|
||||
.markdown-body img,
|
||||
|
@ -99,10 +100,9 @@
|
|||
}
|
||||
</style>
|
||||
<slot></slot>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</slot:head>
|
||||
|
||||
<slot:body>
|
||||
<div class="grid-extra-space">
|
||||
<div class="grid-body-header">
|
||||
<svg height="80px" style="padding-left: 8px;" viewBox="0 0 640 512" version="1.1"
|
||||
|
@ -115,7 +115,7 @@
|
|||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1 class="header-snowpack">{title}</h1>
|
||||
<h1 class="header-snowpack">{context.title}</h1>
|
||||
|
||||
|
||||
<p>
|
||||
|
@ -140,4 +140,4 @@
|
|||
<slot></slot>
|
||||
</article>
|
||||
</div>
|
||||
</body>
|
||||
</slot:body>
|
|
@ -1,16 +1,17 @@
|
|||
<script hmx="setup">
|
||||
export function setup() {
|
||||
<script astro>
|
||||
export const layout = 'layouts/main.hmx';
|
||||
|
||||
export function setup({ context }) {
|
||||
return {
|
||||
title: '404 - Not Found',
|
||||
layout: 'layouts/main.hmx',
|
||||
props: {
|
||||
context: {
|
||||
title: '404 - Not Found',
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<h2 class="content-title">
|
||||
{title}
|
||||
{context.title}
|
||||
</h2>
|
||||
|
||||
<div class="content">
|
||||
|
|
|
@ -1,52 +1,56 @@
|
|||
<script hmx="setup">
|
||||
<script astro>
|
||||
import Card from '../components/Card.jsx';
|
||||
|
||||
export const layout = 'layouts/main.hmx';
|
||||
|
||||
// mocked for now, to be added later
|
||||
// 1. import {paginate} from 'magicthing';
|
||||
// 2. export default function ({paginate}) {
|
||||
function paginate(options) {
|
||||
if (options.tag === 'guide') {
|
||||
return [
|
||||
{title: 'Test guide 1', href:"#"},
|
||||
{title: 'Test guide 2', href:"#"},
|
||||
{ title: 'Test guide 1', href: "#" },
|
||||
{ title: 'Test guide 2', href: "#" },
|
||||
];
|
||||
}
|
||||
if (options.tag === 'communityGuides') {
|
||||
return [{title: 'Test communityGuides', href:"#"}];
|
||||
return [{ title: 'Test communityGuides', href: "#" }];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
export function setup({/* paginate */}) {
|
||||
|
||||
export function setup({ context, /* paginate */ }) {
|
||||
return {
|
||||
title: 'Guides',
|
||||
description: "Snowpack's usage and integration guides.",
|
||||
layout: 'layouts/main.hmx',
|
||||
props: {
|
||||
guides: paginate({
|
||||
files: '/posts/guides/*.md',
|
||||
// sort: ((a, b) => new Date(b) - new Date(a)),
|
||||
tag: 'guide',
|
||||
limit: 10,
|
||||
// page: query.page,
|
||||
}),
|
||||
communityGuides: paginate({
|
||||
files: '/posts/guides/*.md',
|
||||
// sort: ((a, b) => new Date(b) - new Date(a)),
|
||||
tag: 'communityGuides',
|
||||
limit: 10,
|
||||
}),
|
||||
context: {
|
||||
title: 'Guides',
|
||||
description: "Snowpack's usage and integration guides.",
|
||||
props: {
|
||||
guides: paginate({
|
||||
files: '/posts/guides/*.md',
|
||||
// sort: ((a, b) => new Date(b) - new Date(a)),
|
||||
tag: 'guide',
|
||||
limit: 10,
|
||||
// page: query.page,
|
||||
}),
|
||||
communityGuides: paginate({
|
||||
files: '/posts/guides/*.md',
|
||||
// sort: ((a, b) => new Date(b) - new Date(a)),
|
||||
tag: 'communityGuides',
|
||||
limit: 10,
|
||||
}),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<head>
|
||||
<slot:head>
|
||||
|
||||
</head>
|
||||
</slot:head>
|
||||
|
||||
<body>
|
||||
<slot:body>
|
||||
<h2 class="content-title">
|
||||
{title}
|
||||
{context.title}
|
||||
</h2>
|
||||
|
||||
<h3 class="content-title">
|
||||
|
@ -56,13 +60,13 @@
|
|||
<div class="content">
|
||||
<ul>
|
||||
{props.guides.map((post) => {
|
||||
return <li><a href={post.href}>{post.title}</a></li>;
|
||||
return <li><a href={post.href}>{post.title}</a></li>;
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<h3 class="content-title">
|
||||
Popular Integration Guides
|
||||
|
@ -70,7 +74,8 @@
|
|||
|
||||
<div class="card-grid card-grid-4">
|
||||
{props.communityGuides.map((post) => {
|
||||
return <Card item={post} />;
|
||||
return
|
||||
<Card item={post} />;
|
||||
})}
|
||||
</div>
|
||||
</body>
|
||||
</slot:body>
|
|
@ -1,22 +1,21 @@
|
|||
<script hmx="setup">
|
||||
<script astro>
|
||||
import Menu from '../components/Menu.hmx';
|
||||
import Hero from '../components/Hero.hmx';
|
||||
export function setup() {
|
||||
return {
|
||||
layout: 'layouts/base.hmx',
|
||||
props: {}
|
||||
}
|
||||
|
||||
export const layout = 'layouts/base.hmx';
|
||||
export function setup({context}) {
|
||||
return {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<head>
|
||||
<!-- Head Stuff -->
|
||||
</head>
|
||||
<slot:head>
|
||||
<meta charset="AAA" />
|
||||
</slot:head>
|
||||
|
||||
<body>
|
||||
<Hero bar={title}></Hero>
|
||||
<slot:body>
|
||||
<Hero bar={context.title}></Hero>
|
||||
|
||||
<div foo={title} class="container" style="margin: 0 auto">
|
||||
<div foo={context.title} class="container" style="margin: 0 auto">
|
||||
<section class="snow-view__docs is-full is-home">
|
||||
|
||||
<aside id="nav-primary" class="snow-view-nav">
|
||||
|
@ -95,4 +94,4 @@
|
|||
|
||||
<!-- Place this tag in your head or just before your close body tag. -->
|
||||
<script async="async" defer="defer" src="https://buttons.github.io/buttons.js"></script>
|
||||
</body>
|
||||
</slot:body>
|
|
@ -1,31 +1,33 @@
|
|||
<script hmx="setup">
|
||||
<script astro>
|
||||
import Card from '../components/Card.jsx';
|
||||
import CompanyLogo from '../components/CompanyLogo.jsx';
|
||||
import NewsAssets from '../components/NewsAssets.svelte';
|
||||
import NewsTitle from '../components/NewsTitle.vue';
|
||||
|
||||
export const layout = 'layouts/main.hmx';
|
||||
|
||||
import news from '../data/news.json';
|
||||
import users from '../data/users.json';
|
||||
|
||||
export function setup({ findContent }) {
|
||||
export function setup({ context, request }) {
|
||||
console.log(request);
|
||||
return {
|
||||
title: 'Community & News',
|
||||
description: "Snowpack community news and companies that use Snowpack.",
|
||||
layout: 'layouts/main.hmx',
|
||||
// Using Snowpack? Want to be featured on snowpack.dev?
|
||||
// Add your project, organization, or company to the end of this list!
|
||||
props: {
|
||||
context: {
|
||||
title: 'Community & News',
|
||||
description: "Snowpack community news and companies that use Snowpack.",
|
||||
// Using Snowpack? Want to be featured on snowpack.dev?
|
||||
// Add your project, organization, or company to the end of this list!
|
||||
news,
|
||||
users,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<head> </head>
|
||||
<slot:head> </slot:head>
|
||||
|
||||
<body>
|
||||
<NewsTitle title={title} />
|
||||
<slot:body>
|
||||
<NewsTitle title={context.title} />
|
||||
|
||||
<p>
|
||||
Get the latest news, blog posts, and tutorials on Snowpack. <a href="/feed.xml">Also available via RSS.</a>
|
||||
|
@ -45,7 +47,8 @@
|
|||
working on!</div>
|
||||
</article>
|
||||
|
||||
{props.news.reverse().map((item) => <Card:dynamic item={item} />)}
|
||||
{context.news.reverse().map((item) =>
|
||||
<Card:dynamic item={item} />)}
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
|
@ -54,7 +57,8 @@
|
|||
|
||||
<div class="company-logos">
|
||||
|
||||
{props.users.map((user) => <CompanyLogo user={user} />)}
|
||||
{context.users.map((user) =>
|
||||
<CompanyLogo user={user} />)}
|
||||
|
||||
<a href="https://github.com/snowpackjs/snowpack/edit/main/www/_template/news.md" target="_blank"
|
||||
title="Add Your Project/Company!" class="add-company-button">
|
||||
|
@ -70,4 +74,4 @@
|
|||
|
||||
<NewsAssets />
|
||||
</div>
|
||||
</body>
|
||||
</slot:body>
|
|
@ -1,29 +1,24 @@
|
|||
<script hmx="setup">
|
||||
import news from '../data/news.json';
|
||||
import users from '../data/users.json';
|
||||
<script astro>
|
||||
import PluginSearchPage from '../components/PluginSearchPage.jsx';
|
||||
|
||||
export function setup({ findContent }) {
|
||||
export const layout = 'layouts/main.hmx';
|
||||
|
||||
export function setup({ context }) {
|
||||
return {
|
||||
title: 'The Snowpack Plugin Catalog',
|
||||
description: 'Snowpack plugins allow for configuration-minimal tooling integration.',
|
||||
layout: 'layouts/main.hmx',
|
||||
// Using Snowpack? Want to be featured on snowpack.dev?
|
||||
// Add your project, organization, or company to the end of this list!
|
||||
props: {
|
||||
news,
|
||||
users,
|
||||
context: {
|
||||
title: 'The Snowpack Plugin Catalog',
|
||||
description: 'Snowpack plugins allow for configuration-minimal tooling integration.',
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<slot:head>
|
||||
</slot:head>
|
||||
|
||||
<slot:body>
|
||||
<h2 class="content-title">
|
||||
{ title }
|
||||
{ context.title }
|
||||
</h2>
|
||||
|
||||
<h3 class="pluginPage-subheading">Customize Snowpack with optimized build plugins.</h3>
|
||||
|
@ -33,4 +28,4 @@
|
|||
</p>
|
||||
|
||||
<PluginSearchPage:dynamic />
|
||||
</body>
|
||||
</slot:body>
|
|
@ -1,4 +1,4 @@
|
|||
<script hmx="setup">
|
||||
<script astro>
|
||||
import Subnav from '../components/Subnav.hmx';
|
||||
import { content as Menu } from '../components/Menu.hmx';
|
||||
// import contentful from 'skypack:contentful';
|
||||
|
@ -16,12 +16,12 @@
|
|||
<Menu />
|
||||
</aside>
|
||||
|
||||
<Subnav title={title} />
|
||||
<Subnav title={context.title} headers={context.content.headers} />
|
||||
|
||||
<article class="snow-view-main">
|
||||
<div class="content">
|
||||
<h2 class="content-title">
|
||||
{title}
|
||||
{context.title}
|
||||
</h2>
|
||||
<div class="content-layout">
|
||||
<div class="content-body">
|
||||
|
|
21
package-lock.json
generated
21
package-lock.json
generated
|
@ -167,6 +167,12 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz",
|
||||
"integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg=="
|
||||
},
|
||||
"@types/github-slugger": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/github-slugger/-/github-slugger-1.3.0.tgz",
|
||||
"integrity": "sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
|
||||
|
@ -1562,6 +1568,21 @@
|
|||
"pump": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"github-slugger": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.3.0.tgz",
|
||||
"integrity": "sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q==",
|
||||
"requires": {
|
||||
"emoji-regex": ">=6.0.0 <=6.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"emoji-regex": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.1.tgz",
|
||||
"integrity": "sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4="
|
||||
}
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
"deepmerge": "^4.2.2",
|
||||
"domhandler": "^4.0.0",
|
||||
"es-module-lexer": "^0.4.1",
|
||||
"github-slugger": "^1.3.0",
|
||||
"gray-matter": "^4.0.2",
|
||||
"htmlparser2": "^6.0.0",
|
||||
"kleur": "^4.1.4",
|
||||
|
@ -54,6 +55,7 @@
|
|||
"yargs-parser": "^20.2.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/github-slugger": "^1.3.0",
|
||||
"@types/sass": "^1.16.0",
|
||||
"@types/yargs-parser": "^20.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||
|
|
|
@ -12,58 +12,10 @@ module.exports = function (snowpackConfig, { resolve } = {}) {
|
|||
output: ['.js'],
|
||||
},
|
||||
async load({ filePath }) {
|
||||
const { compilePage, compileComponent } = await transformPromise;
|
||||
const { compileComponent } = await transformPromise;
|
||||
const projectRoot = snowpackConfig.root;
|
||||
const contents = await readFile(filePath, 'utf-8');
|
||||
|
||||
if (!filePath.includes('/pages/') && !filePath.includes('/layouts/')) {
|
||||
const result = await compileComponent(contents, { compileOptions: { resolve }, filename: filePath, projectRoot });
|
||||
return result.contents;
|
||||
}
|
||||
const result = await compilePage(contents, {
|
||||
compileOptions: { resolve },
|
||||
filename: filePath,
|
||||
projectRoot,
|
||||
});
|
||||
|
||||
try {
|
||||
return /* js */ `
|
||||
${result.contents}
|
||||
|
||||
export default async (childDatas, childRenderFns) => {
|
||||
// Kind of hacky, can clean up if this works
|
||||
const renderHmx = {setup, head, body};
|
||||
const merge = (await import('deepmerge')).default;
|
||||
const content = childDatas && childDatas[0].content;
|
||||
const _data = await renderHmx.setup({content});
|
||||
if (_data.layout) {
|
||||
const renderLayout = (await import('/_hmx/layouts/' + _data.layout.replace(/.*layouts\\//, "").replace(/\.hmx$/, '.js'))).default;
|
||||
return renderLayout(
|
||||
[...(childDatas || []), _data],
|
||||
[...(childRenderFns || []), renderHmx]
|
||||
);
|
||||
}
|
||||
const data = merge.all([_data, ...(childDatas || [])]);
|
||||
let headResult;
|
||||
let bodyResult;
|
||||
for (const renderFn of (childRenderFns || [])) {
|
||||
let headAndBody = await Promise.all([
|
||||
renderFn.head(data, headResult),
|
||||
renderFn.body(data, bodyResult)
|
||||
]);
|
||||
headResult = headAndBody[0];
|
||||
bodyResult = headAndBody[1];
|
||||
}
|
||||
return h(Fragment, null, [
|
||||
renderHmx.head(data, headResult, true),
|
||||
renderHmx.body(data, bodyResult, true),
|
||||
]);
|
||||
};
|
||||
`;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return result.contents;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -17,9 +17,12 @@ export interface JsxItem {
|
|||
|
||||
export interface TransformResult {
|
||||
script: string;
|
||||
head: JsxItem | undefined;
|
||||
body: JsxItem | undefined;
|
||||
items: JsxItem[];
|
||||
}
|
||||
|
||||
export interface CompileResult {
|
||||
result: TransformResult;
|
||||
contents: string;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,10 @@ function getAttributes(attrs: Attribute[]): Record<string, string> {
|
|||
continue;
|
||||
}
|
||||
const val: TemplateNode = attr.value[0];
|
||||
if (!val) {
|
||||
result[attr.name] = '(' + val + ')';
|
||||
continue;
|
||||
}
|
||||
switch (val.type) {
|
||||
case 'MustacheTag':
|
||||
result[attr.name] = '(' + val.expression + ')';
|
||||
|
@ -143,33 +147,37 @@ function getComponentWrapper(_name: string, { type, url }: { type: string; url:
|
|||
}
|
||||
|
||||
function compileScriptSafe(raw: string, loader: 'jsx' | 'tsx'): string {
|
||||
let compiledCode = compileExpressionSafe(raw, loader);
|
||||
// esbuild treeshakes unused imports. In our case these are components, so let's keep them.
|
||||
const imports = eslexer
|
||||
.parse(raw)[0]
|
||||
.filter(({ d }) => d === -1)
|
||||
.map((i: any) => raw.substring(i.ss, i.se));
|
||||
.parse(raw)[0]
|
||||
.filter(({ d }) => d === -1)
|
||||
.map((i) => raw.substring(i.ss, i.se));
|
||||
for (let importStatement of imports) {
|
||||
if (!compiledCode.includes(importStatement)) {
|
||||
compiledCode = importStatement + '\n' + compiledCode;
|
||||
}
|
||||
}
|
||||
return compiledCode;
|
||||
}
|
||||
|
||||
|
||||
function compileExpressionSafe(raw: string, loader: 'jsx' | 'tsx'): string {
|
||||
let { code } = transformSync(raw, {
|
||||
loader,
|
||||
jsxFactory: 'h',
|
||||
jsxFragment: 'Fragment',
|
||||
charset: 'utf8',
|
||||
});
|
||||
|
||||
for (let importStatement of imports) {
|
||||
if (!code.includes(importStatement)) {
|
||||
code = importStatement + '\n' + code;
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
|
||||
}
|
||||
|
||||
export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Promise<TransformResult> {
|
||||
await eslexer.init;
|
||||
|
||||
// Compile scripts as TypeScript, always
|
||||
const script = compileScriptSafe(ast.instance ? ast.instance.content : '', 'tsx');
|
||||
const script = compileScriptSafe(ast.module ? ast.module.content : '', 'tsx');
|
||||
|
||||
// Todo: Validate that `h` and `Fragment` aren't defined in the script
|
||||
const [scriptImports] = eslexer.parse(script, 'optional-sourcename');
|
||||
|
@ -182,6 +190,8 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
|
|||
);
|
||||
|
||||
const additionalImports = new Set<string>();
|
||||
let headItem: JsxItem | undefined;
|
||||
let bodyItem: JsxItem | undefined;
|
||||
let items: JsxItem[] = [];
|
||||
let mode: 'JSX' | 'SCRIPT' | 'SLOT' = 'JSX';
|
||||
let collectionItem: JsxItem | undefined;
|
||||
|
@ -192,7 +202,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
|
|||
enter(node: TemplateNode) {
|
||||
switch (node.type) {
|
||||
case 'MustacheTag':
|
||||
let code = compileScriptSafe(node.expression, 'jsx');
|
||||
let code = compileExpressionSafe(node.expression, 'jsx');
|
||||
|
||||
let matches: RegExpExecArray[] = [];
|
||||
let match: RegExpExecArray | null | undefined;
|
||||
|
@ -230,8 +240,12 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
|
|||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Head':
|
||||
case 'Body':
|
||||
case 'InlineComponent':
|
||||
case 'Element':
|
||||
case 'Title':
|
||||
case 'Element': {
|
||||
const name: string = node.name;
|
||||
if (!name) {
|
||||
throw new Error('AHHHH');
|
||||
|
@ -241,6 +255,16 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
|
|||
currentItemName = name;
|
||||
if (!collectionItem) {
|
||||
collectionItem = { name, jsx: '' };
|
||||
if (node.type === 'Head') {
|
||||
collectionItem.jsx += `h(Fragment, null`;
|
||||
headItem = collectionItem;
|
||||
return;
|
||||
}
|
||||
if (node.type === 'Body') {
|
||||
collectionItem.jsx += `h(Fragment, null`;
|
||||
bodyItem = collectionItem;
|
||||
return;
|
||||
}
|
||||
items.push(collectionItem);
|
||||
}
|
||||
collectionItem.jsx += collectionItem.jsx === '' ? '' : ',';
|
||||
|
@ -249,10 +273,6 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
|
|||
collectionItem.jsx += `h("${name}", ${attributes ? generateAttributes(attributes) : 'null'}`;
|
||||
return;
|
||||
}
|
||||
if (name === 'Component') {
|
||||
collectionItem.jsx += `h(Fragment, null`;
|
||||
return;
|
||||
}
|
||||
const [componentName, componentKind] = name.split(':');
|
||||
const componentImportData = components[componentName];
|
||||
if (!componentImportData) {
|
||||
|
@ -265,6 +285,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
|
|||
|
||||
collectionItem.jsx += `h(${wrapper}, ${attributes ? generateAttributes(attributes) : 'null'}`;
|
||||
return;
|
||||
}
|
||||
case 'Attribute': {
|
||||
this.skip();
|
||||
return;
|
||||
|
@ -293,7 +314,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
|
|||
return;
|
||||
}
|
||||
default:
|
||||
throw new Error('Unexpected node type: ' + node.type);
|
||||
throw new Error('Unexpected (enter) node type: ' + node.type);
|
||||
}
|
||||
},
|
||||
leave(node, parent, prop, index) {
|
||||
|
@ -314,6 +335,9 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
|
|||
if (!collectionItem) {
|
||||
return;
|
||||
}
|
||||
case 'Head':
|
||||
case 'Body':
|
||||
case 'Title':
|
||||
case 'Element':
|
||||
case 'InlineComponent':
|
||||
if (!collectionItem) {
|
||||
|
@ -329,13 +353,15 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
|
|||
return;
|
||||
}
|
||||
default:
|
||||
throw new Error('Unexpected node type: ' + node.type);
|
||||
throw new Error('Unexpected (leave) node type: ' + node.type);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
script: script + '\n' + Array.from(additionalImports).join('\n'),
|
||||
head: headItem,
|
||||
body: bodyItem,
|
||||
items,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ export interface Parser {
|
|||
|
||||
export interface Script extends BaseNode {
|
||||
type: 'Script';
|
||||
context: string;
|
||||
context: 'runtime' | 'setup';
|
||||
content: string;
|
||||
}
|
||||
|
||||
|
@ -75,8 +75,8 @@ export interface Style extends BaseNode {
|
|||
export interface Ast {
|
||||
html: TemplateNode;
|
||||
css: Style;
|
||||
instance: Script;
|
||||
module: Script;
|
||||
// instance: Script;
|
||||
}
|
||||
|
||||
export interface Warning {
|
||||
|
@ -94,38 +94,6 @@ export type ModuleFormat = 'esm' | 'cjs';
|
|||
|
||||
export type CssHashGetter = (args: { name: string; filename: string | undefined; css: string; hash: (input: string) => string }) => string;
|
||||
|
||||
export interface CompileOptions {
|
||||
format?: ModuleFormat;
|
||||
name?: string;
|
||||
filename?: string;
|
||||
generate?: 'dom' | 'ssr' | false;
|
||||
|
||||
sourcemap?: object | string;
|
||||
outputFilename?: string;
|
||||
cssOutputFilename?: string;
|
||||
sveltePath?: string;
|
||||
|
||||
dev?: boolean;
|
||||
accessors?: boolean;
|
||||
immutable?: boolean;
|
||||
hydratable?: boolean;
|
||||
legacy?: boolean;
|
||||
customElement?: boolean;
|
||||
tag?: string;
|
||||
css?: boolean;
|
||||
loopGuardTimeout?: number;
|
||||
namespace?: string;
|
||||
cssHash?: CssHashGetter;
|
||||
|
||||
preserveComments?: boolean;
|
||||
preserveWhitespace?: boolean;
|
||||
}
|
||||
|
||||
export interface ParserOptions {
|
||||
filename?: string;
|
||||
customElement?: boolean;
|
||||
}
|
||||
|
||||
export interface Visitor {
|
||||
enter: (node: Node) => void;
|
||||
leave?: (node: Node) => void;
|
||||
|
|
|
@ -232,33 +232,34 @@ export default function parse(template: string, options: ParserOptions = {}): As
|
|||
);
|
||||
}
|
||||
|
||||
const instance_scripts = parser.js.filter((script) => script.context === 'default');
|
||||
const module_scripts = parser.js.filter((script) => script.context === 'module');
|
||||
// const instance_scripts = parser.js.filter((script) => script.context === 'default');
|
||||
// const module_scripts = parser.js.filter((script) => script.context === 'module');
|
||||
const hmx_scripts = parser.js.filter((script) => script.context === 'setup');
|
||||
|
||||
if (instance_scripts.length > 1) {
|
||||
if (hmx_scripts.length > 1) {
|
||||
parser.error(
|
||||
{
|
||||
code: 'invalid-script',
|
||||
message: 'A component can only have one instance-level <script> element',
|
||||
message: 'A component can only have one <script astro> element',
|
||||
},
|
||||
instance_scripts[1].start
|
||||
hmx_scripts[1].start
|
||||
);
|
||||
}
|
||||
|
||||
if (module_scripts.length > 1) {
|
||||
parser.error(
|
||||
{
|
||||
code: 'invalid-script',
|
||||
message: 'A component can only have one <script context="module"> element',
|
||||
},
|
||||
module_scripts[1].start
|
||||
);
|
||||
}
|
||||
// if (module_scripts.length > 1) {
|
||||
// parser.error(
|
||||
// {
|
||||
// code: 'invalid-script',
|
||||
// message: 'A component can only have one <script context="module"> element',
|
||||
// },
|
||||
// module_scripts[1].start
|
||||
// );
|
||||
// }
|
||||
|
||||
return {
|
||||
html: parser.html,
|
||||
css: parser.css[0],
|
||||
instance: instance_scripts[0],
|
||||
module: module_scripts[0],
|
||||
// instance: instance_scripts[0],
|
||||
module: hmx_scripts[0],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,15 +7,16 @@ import { Node, Program } from 'estree';
|
|||
|
||||
const script_closing_tag = '</script>';
|
||||
|
||||
function get_context(parser: Parser, attributes: any[], start: number): string {
|
||||
const context = attributes.find((attribute) => attribute.name === 'context');
|
||||
if (!context) return 'default';
|
||||
function get_context(parser: Parser, attributes: any[], start: number): 'runtime' | 'setup' {
|
||||
const context = attributes.find((attribute) => attribute.name === 'astro');
|
||||
if (!context) return 'runtime';
|
||||
if (context.value === true) return 'setup';
|
||||
|
||||
if (context.value.length !== 1 || context.value[0].type !== 'Text') {
|
||||
parser.error(
|
||||
{
|
||||
code: 'invalid-script',
|
||||
message: 'context attribute must be static',
|
||||
message: 'astro attribute must be static',
|
||||
},
|
||||
start
|
||||
);
|
||||
|
@ -23,11 +24,11 @@ function get_context(parser: Parser, attributes: any[], start: number): string {
|
|||
|
||||
const value = context.value[0].data;
|
||||
|
||||
if (value !== 'module') {
|
||||
if (value !== 'setup') {
|
||||
parser.error(
|
||||
{
|
||||
code: 'invalid-script',
|
||||
message: 'If the context attribute is supplied, its value must be "module"',
|
||||
message: 'If the "astro" attribute has a value, its value must be "setup"',
|
||||
},
|
||||
context.start
|
||||
);
|
||||
|
|
|
@ -14,13 +14,14 @@ import list from '../../utils/list.js';
|
|||
const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/;
|
||||
|
||||
const meta_tags = new Map([
|
||||
['svelte:head', 'Head'],
|
||||
['svelte:options', 'Options'],
|
||||
['svelte:window', 'Window'],
|
||||
['svelte:body', 'Body'],
|
||||
['slot:head', 'Head'],
|
||||
['slot:body', 'Body'],
|
||||
// ['astro:options', 'Options'],
|
||||
// ['astro:window', 'Window'],
|
||||
// ['astro:body', 'Body'],
|
||||
]);
|
||||
|
||||
const valid_meta_tags = Array.from(meta_tags.keys()).concat('svelte:self', 'svelte:component', 'svelte:fragment');
|
||||
const valid_meta_tags = Array.from(meta_tags.keys()); //.concat('astro:self', 'astro:component', 'astro:fragment');
|
||||
|
||||
const specials = new Map([
|
||||
[
|
||||
|
@ -39,9 +40,10 @@ const specials = new Map([
|
|||
],
|
||||
]);
|
||||
|
||||
const SELF = /^svelte:self(?=[\s/>])/;
|
||||
const COMPONENT = /^svelte:component(?=[\s/>])/;
|
||||
const SLOT = /^svelte:fragment(?=[\s/>])/;
|
||||
const SELF = /^astro:self(?=[\s/>])/;
|
||||
const COMPONENT = /^astro:component(?=[\s/>])/;
|
||||
const SLOT = /^astro:fragment(?=[\s/>])/;
|
||||
const HEAD = /^head(?=[\s/>])/;
|
||||
|
||||
function parent_is_head(stack) {
|
||||
let i = stack.length;
|
||||
|
@ -79,7 +81,7 @@ export default function tag(parser: Parser) {
|
|||
if (meta_tags.has(name)) {
|
||||
const slug = meta_tags.get(name).toLowerCase();
|
||||
if (is_closing_tag) {
|
||||
if ((name === 'svelte:window' || name === 'svelte:body') && parser.current().children.length) {
|
||||
if ((name === 'astro:window' || name === 'astro:body') && parser.current().children.length) {
|
||||
parser.error(
|
||||
{
|
||||
code: `invalid-${slug}-content`,
|
||||
|
@ -115,9 +117,9 @@ export default function tag(parser: Parser) {
|
|||
|
||||
const type = meta_tags.has(name)
|
||||
? meta_tags.get(name)
|
||||
: /[A-Z]/.test(name[0]) || name === 'svelte:self' || name === 'svelte:component'
|
||||
: /[A-Z]/.test(name[0]) || name === 'astro:self' || name === 'astro:component'
|
||||
? 'InlineComponent'
|
||||
: name === 'svelte:fragment'
|
||||
: name === 'astro:fragment'
|
||||
? 'SlotTemplate'
|
||||
: name === 'title' && parent_is_head(parser.stack)
|
||||
? 'Title'
|
||||
|
@ -197,13 +199,13 @@ export default function tag(parser: Parser) {
|
|||
parser.allow_whitespace();
|
||||
}
|
||||
|
||||
if (name === 'svelte:component') {
|
||||
if (name === 'astro:component') {
|
||||
const index = element.attributes.findIndex((attr) => attr.type === 'Attribute' && attr.name === 'this');
|
||||
if (!~index) {
|
||||
parser.error(
|
||||
{
|
||||
code: 'missing-component-definition',
|
||||
message: "<svelte:component> must have a 'this' attribute",
|
||||
message: "<astro:component> must have a 'this' attribute",
|
||||
},
|
||||
start
|
||||
);
|
||||
|
@ -281,27 +283,29 @@ function read_tag_name(parser: Parser) {
|
|||
parser.error(
|
||||
{
|
||||
code: 'invalid-self-placement',
|
||||
message: '<svelte:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components',
|
||||
message: '<astro:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components',
|
||||
},
|
||||
start
|
||||
);
|
||||
}
|
||||
|
||||
return 'svelte:self';
|
||||
return 'astro:self';
|
||||
}
|
||||
|
||||
if (parser.read(COMPONENT)) return 'svelte:component';
|
||||
if (parser.read(COMPONENT)) return 'astro:component';
|
||||
|
||||
if (parser.read(SLOT)) return 'svelte:fragment';
|
||||
if (parser.read(SLOT)) return 'astro:fragment';
|
||||
|
||||
if (parser.read(HEAD)) return 'head';
|
||||
|
||||
const name = parser.read_until(/(\s|\/|>)/);
|
||||
|
||||
if (meta_tags.has(name)) return name;
|
||||
|
||||
if (name.startsWith('svelte:')) {
|
||||
if (name.startsWith('astro:')) {
|
||||
const match = fuzzymatch(name.slice(7), valid_meta_tags);
|
||||
|
||||
let message = `Valid <svelte:...> tag names are ${list(valid_meta_tags)}`;
|
||||
let message = `Valid <astro:...> tag names are ${list(valid_meta_tags)}`;
|
||||
if (match) message += ` (did you mean '${match}'?)`;
|
||||
|
||||
parser.error(
|
||||
|
|
|
@ -52,6 +52,7 @@ export default async function (astroConfig: AstroConfig) {
|
|||
await writeFile(outPath, html, 'utf-8');
|
||||
} catch (err) {
|
||||
console.error('Unable to generate page', rel);
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
import type { HtmlExtension, Token } from 'micromark/dist/shared-types';
|
||||
|
||||
const characterReferences = {
|
||||
'"': 'quot',
|
||||
'&': 'amp',
|
||||
'<': 'lt',
|
||||
'>': 'gt',
|
||||
'{': 'lbrace',
|
||||
'}': 'rbrace',
|
||||
};
|
||||
|
||||
type EncodedChars = '"' | '&' | '<' | '>' | '{' | '}';
|
||||
|
||||
function encode(value: string): string {
|
||||
return value.replace(/["&<>{}]/g, (raw: string) => {
|
||||
return '&' + characterReferences[raw as EncodedChars] + ';';
|
||||
});
|
||||
}
|
||||
|
||||
const plugin: HtmlExtension = {
|
||||
exit: {
|
||||
codeFlowValue() {
|
||||
const token: Token = arguments[0];
|
||||
const serialize = (this.sliceSerialize as unknown) as (t: Token) => string;
|
||||
const raw = (this.raw as unknown) as (s: string) => void;
|
||||
const value = serialize(token);
|
||||
raw(encode(value));
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export { plugin as default };
|
35
src/micromark-collect-headers.ts
Normal file
35
src/micromark-collect-headers.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import slugger from 'github-slugger';
|
||||
|
||||
// NOTE: micromark has terrible TS types. Instead of fighting with the
|
||||
// limited/broken TS types that they ship, we just reach for our good friend, "any".
|
||||
export function createMarkdownHeadersCollector() {
|
||||
const headers: any[] = [];
|
||||
let currentHeader: any;
|
||||
return {
|
||||
headers,
|
||||
headersExtension: {
|
||||
enter: {
|
||||
atxHeading(node: any) {
|
||||
currentHeader = {};
|
||||
headers.push(currentHeader);
|
||||
},
|
||||
atxHeadingSequence(node: any) {
|
||||
currentHeader.depth = this.sliceSerialize(node).length;
|
||||
},
|
||||
atxHeadingText(node: any) {
|
||||
currentHeader.text = this.sliceSerialize(node);
|
||||
},
|
||||
} as any,
|
||||
exit: {
|
||||
atxHeading(node: any) {
|
||||
currentHeader.slug = slugger.slug(currentHeader.text);
|
||||
this.tag(`<h${currentHeader.depth} id="${currentHeader.slug}">`);
|
||||
this.raw(currentHeader.text);
|
||||
this.tag(`</h${currentHeader.depth}>`);
|
||||
|
||||
// console.log(this.sliceSerialize(node));
|
||||
},
|
||||
} as any,
|
||||
} as any,
|
||||
};
|
||||
}
|
|
@ -58,7 +58,14 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro
|
|||
|
||||
try {
|
||||
const mod = await snowpackRuntime.importModule(selectedPageUrl);
|
||||
const html = (await mod.exports.default()) as string;
|
||||
const html = (await mod.exports.__renderPage({
|
||||
request: {
|
||||
host: fullurl.hostname,
|
||||
path: fullurl.pathname,
|
||||
href: fullurl.toString(),
|
||||
},
|
||||
children: [],
|
||||
})) as string;
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
|
|
@ -7,7 +7,7 @@ import matter from 'gray-matter';
|
|||
import gfmHtml from 'micromark-extension-gfm/html.js';
|
||||
import { CompileResult, TransformResult } from './@types/astro';
|
||||
import { parse } from './compiler/index.js';
|
||||
import markdownEncode from './markdown-encode.js';
|
||||
import { createMarkdownHeadersCollector } from './micromark-collect-headers.js';
|
||||
import { defaultLogOptions } from './logger.js';
|
||||
import { optimize } from './optimize/index.js';
|
||||
import { codegen } from './codegen/index.js';
|
||||
|
@ -51,33 +51,35 @@ async function convertMdToJsx(
|
|||
contents: string,
|
||||
{ compileOptions, filename, fileID }: { compileOptions: CompileOptions; filename: string; fileID: string }
|
||||
): Promise<TransformResult> {
|
||||
// This doesn't work.
|
||||
const { data: _frontmatterData, content } = matter(contents);
|
||||
const {headers, headersExtension} = createMarkdownHeadersCollector();
|
||||
const mdHtml = micromark(content, {
|
||||
extensions: [gfmSyntax()],
|
||||
htmlExtensions: [gfmHtml, markdownEncode],
|
||||
htmlExtensions: [gfmHtml, headersExtension],
|
||||
});
|
||||
|
||||
const setupData = {
|
||||
title: _frontmatterData.title,
|
||||
description: _frontmatterData.description,
|
||||
layout: _frontmatterData.layout,
|
||||
console.log("headers", headers);
|
||||
const setupContext = {
|
||||
..._frontmatterData,
|
||||
content: {
|
||||
frontmatter: _frontmatterData,
|
||||
|
||||
// This is an awful hack due to Svelte parser disliking script tags badly.
|
||||
source: content.replace(/<\/?script/g, '<SCRIPT'),
|
||||
headers,
|
||||
source: content,
|
||||
html: mdHtml,
|
||||
},
|
||||
props: {
|
||||
..._frontmatterData,
|
||||
},
|
||||
};
|
||||
|
||||
// </script> can't be anywhere inside of a JS string, otherwise the HTML parser fails.
|
||||
// Break it up here so that the HTML parser won't detect it.
|
||||
const stringifiedSetupContext = JSON.stringify(setupContext).replace(/\<\/script\>/g, `</scrip" + "t>`);
|
||||
|
||||
return convertHmxToJsx(
|
||||
`<script hmx="setup">export function setup() {
|
||||
return ${JSON.stringify(setupData)};
|
||||
}</script><head></head><body>${mdHtml}</body>`,
|
||||
`<script astro>
|
||||
${_frontmatterData.layout ? `export const layout = ${JSON.stringify(_frontmatterData.layout)};` : ''}
|
||||
export function setup({context}) {
|
||||
return {context: ${stringifiedSetupContext} };
|
||||
}
|
||||
</script><slot:head></slot:head><slot:body><section>{${JSON.stringify(mdHtml)}}</section></slot:body>`,
|
||||
{ compileOptions, filename, fileID }
|
||||
);
|
||||
}
|
||||
|
@ -97,49 +99,85 @@ async function transformFromSource(
|
|||
}
|
||||
}
|
||||
|
||||
export async function compilePage(
|
||||
source: string,
|
||||
{ compileOptions = defaultCompileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string }
|
||||
): Promise<CompileResult> {
|
||||
const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
|
||||
|
||||
const headItem = sourceJsx.items.find((item) => item.name === 'head');
|
||||
const bodyItem = sourceJsx.items.find((item) => item.name === 'body');
|
||||
const headItemJsx = !headItem ? 'null' : headItem.jsx.replace('"head"', 'isRoot ? "head" : Fragment');
|
||||
const bodyItemJsx = !bodyItem ? 'null' : bodyItem.jsx.replace('"head"', 'isRoot ? "body" : Fragment');
|
||||
|
||||
const modJsx = `
|
||||
${sourceJsx.script}
|
||||
|
||||
import { h, Fragment } from '${internalImport('h.js')}';
|
||||
export function head({title, description, props}, child, isRoot) { return (${headItemJsx}); }
|
||||
export function body({title, description, props}, child, isRoot) { return (${bodyItemJsx}); }
|
||||
`.trim();
|
||||
|
||||
return {
|
||||
contents: modJsx,
|
||||
};
|
||||
}
|
||||
|
||||
export async function compileComponent(
|
||||
source: string,
|
||||
{ compileOptions = defaultCompileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string }
|
||||
): Promise<CompileResult> {
|
||||
const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
|
||||
|
||||
// throw error if <Component /> missing
|
||||
if (!sourceJsx.items.find(({ name }) => name === 'Component')) throw new Error(`${filename} <Component> expected!`);
|
||||
const headItem = sourceJsx.head;
|
||||
const bodyItem = sourceJsx.body;
|
||||
const headItemJsx = !headItem ? 'null' : headItem.jsx;
|
||||
const bodyItemJsx = !bodyItem ? 'null' : bodyItem.jsx;
|
||||
|
||||
// sort <style> tags first
|
||||
// TODO: remove these and inject in <head>
|
||||
sourceJsx.items.sort((a, b) => (a.name === 'style' && b.name !== 'style' ? -1 : 0));
|
||||
|
||||
// return template
|
||||
const modJsx = `
|
||||
import { h, Fragment } from '${internalImport('h.js')}';
|
||||
export default function(props) { return h(Fragment, null, ${sourceJsx.items.map(({ jsx }) => jsx).join(',')}); }
|
||||
`.trim();
|
||||
let modJsx = `
|
||||
// <script astro></script>
|
||||
${sourceJsx.script}
|
||||
|
||||
// \`__render()\`: Render the contents of the HMX module. "<slot:*>" elements are not
|
||||
// included (see below).
|
||||
import { h, Fragment } from '${internalImport('h.js')}';
|
||||
export default function __render(props) { return h(Fragment, null, ${sourceJsx.items.map(({ jsx }) => jsx).join(',')}); }
|
||||
|
||||
// <slot:*> render functions
|
||||
export function __slothead(context, child) { return h(Fragment, null, ${headItemJsx}); }
|
||||
export function __slotbody(context, child) { return h(Fragment, null, ${bodyItemJsx}); }
|
||||
`;
|
||||
|
||||
if (headItemJsx || bodyItemJsx) {
|
||||
modJsx += `
|
||||
// \`__renderPage()\`: Render the contents of the HMX module as a page. This is a special flow,
|
||||
// triggered by loading a component directly by URL.
|
||||
// If the page exports a defined "layout", then load + render those first. "context", "slot:head",
|
||||
// and "slot:body" should all inherit from parent layouts, merging together in the correct order.
|
||||
export async function __renderPage({request, children}) {
|
||||
const currentChild = {
|
||||
__slothead,
|
||||
__slotbody,
|
||||
setup: typeof setup === 'undefined' ? (passthrough) => passthrough : setup,
|
||||
layout: typeof layout === 'undefined' ? undefined : layout,
|
||||
};
|
||||
|
||||
// find all layouts, going up the layout chain.
|
||||
if (currentChild.layout) {
|
||||
const layoutComponent = (await import('/_hmx/layouts/' + layout.replace(/.*layouts\\//, "").replace(/\.hmx$/, '.js')));
|
||||
return layoutComponent.__renderPage({
|
||||
request,
|
||||
children: [currentChild, ...children],
|
||||
});
|
||||
}
|
||||
|
||||
const isRoot = true;
|
||||
const merge = (await import('deepmerge')).default;
|
||||
|
||||
// call all children setup scripts, in order, and return.
|
||||
let mergedContext = {};
|
||||
for (const child of [currentChild, ...children]) {
|
||||
const childSetupResult = await child.setup({request, context: mergedContext});
|
||||
mergedContext = childSetupResult.context ? merge(mergedContext, childSetupResult.context) : mergedContext;
|
||||
}
|
||||
|
||||
Object.freeze(mergedContext);
|
||||
|
||||
let headResult;
|
||||
let bodyResult;
|
||||
for (const child of children.reverse()) {
|
||||
headResult = await child.__slothead(mergedContext, headResult);
|
||||
bodyResult = await child.__slotbody(mergedContext, bodyResult);
|
||||
}
|
||||
return h(Fragment, null, [
|
||||
h("head", null, currentChild.__slothead(mergedContext, headResult)),
|
||||
h("body", null, currentChild.__slotbody(mergedContext, bodyResult)),
|
||||
]);
|
||||
};\n`;
|
||||
}
|
||||
|
||||
return {
|
||||
result: sourceJsx,
|
||||
contents: modJsx,
|
||||
};
|
||||
}
|
||||
|
|
10
test/fixtures/hmx-basic/astro/pages/index.hmx
vendored
10
test/fixtures/hmx-basic/astro/pages/index.hmx
vendored
|
@ -1,4 +1,4 @@
|
|||
<script hmx="setup">
|
||||
<script astro>
|
||||
export function setup() {
|
||||
return {
|
||||
props: {}
|
||||
|
@ -6,10 +6,10 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<head>
|
||||
<slot:head>
|
||||
<!-- Head Stuff -->
|
||||
</head>
|
||||
</slot:head>
|
||||
|
||||
<body>
|
||||
<slot:body>
|
||||
<h1>Hello world!</h1>
|
||||
</body>
|
||||
</slot:body>
|
Loading…
Reference in a new issue