mirror of
https://github.com/modernweb-dev/rocket.git
synced 2026-03-21 15:54:57 +00:00
Compare commits
61 Commits
@rocket/co
...
@rocket/cl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
340bf8e653 | ||
|
|
eae200708d | ||
|
|
f707f636fa | ||
|
|
814b5d29ad | ||
|
|
e1e96acceb | ||
|
|
7543a129cf | ||
|
|
60e85a17a7 | ||
|
|
fd8f97859a | ||
|
|
56fdb0cbd4 | ||
|
|
e6d9c74510 | ||
|
|
c338696482 | ||
|
|
2ff4b4c542 | ||
|
|
ba64b45ebf | ||
|
|
e437e02cb9 | ||
|
|
ce9b12edd4 | ||
|
|
d034f799c0 | ||
|
|
8bba4a88c8 | ||
|
|
c7261aa2b0 | ||
|
|
690075d335 | ||
|
|
2724f073fc | ||
|
|
d08692c7f3 | ||
|
|
2b7f1ee719 | ||
|
|
3802778be4 | ||
|
|
26f4a1ebff | ||
|
|
81edf45fe2 | ||
|
|
c5a1d7e8d1 | ||
|
|
74dd8d1bcc | ||
|
|
72f631ac86 | ||
|
|
fafb99b0fa | ||
|
|
f5769b9aa9 | ||
|
|
12d9cc3b44 | ||
|
|
ef9b373aa1 | ||
|
|
560234d663 | ||
|
|
024514e901 | ||
|
|
66c2d781e6 | ||
|
|
14721d1e0f | ||
|
|
0f6709ac4b | ||
|
|
ed86ff2346 | ||
|
|
c675820163 | ||
|
|
f4a0ab559f | ||
|
|
a8cdaebab1 | ||
|
|
22393dd172 | ||
|
|
a6fdb31f1e | ||
|
|
dd15d4fc65 | ||
|
|
edb1abf82b | ||
|
|
0b6411661e | ||
|
|
604a80e6cb | ||
|
|
fe6a929f1e | ||
|
|
2267e728cf | ||
|
|
abc8a02b72 | ||
|
|
2270887faf | ||
|
|
bad4686506 | ||
|
|
818caad7cb | ||
|
|
672b7e893e | ||
|
|
a8e66d84f4 | ||
|
|
e9090d64b9 | ||
|
|
728a205b7b | ||
|
|
67ba29d45a | ||
|
|
758caffdf9 | ||
|
|
302227e8a9 | ||
|
|
04a31220fb |
10
docs/_assets/body.css
Normal file
10
docs/_assets/body.css
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
html {
|
||||||
|
--demo-background-color: #eee;
|
||||||
|
--demo-color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[theme="dark"] body {
|
||||||
|
background: #333;
|
||||||
|
--demo-background-color: #888;
|
||||||
|
--demo-color: #eee;
|
||||||
|
}
|
||||||
@@ -7,3 +7,5 @@
|
|||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
/>
|
/>
|
||||||
<meta name="twitter:creator" content="@modern_web_dev" />
|
<meta name="twitter:creator" content="@modern_web_dev" />
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="{{ '/_assets/body.css' | asset | url }}" mdjs-use>
|
||||||
|
|||||||
223
docs/docs/configuration/images.md
Normal file
223
docs/docs/configuration/images.md
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
# Configuration >> Images ||40
|
||||||
|
|
||||||
|
Rocket does handle content images automatically by
|
||||||
|
|
||||||
|
- producing multiple sizes so users download images that are meant for their resolution
|
||||||
|
- outputting multiple formats so the device can choose the best image format it supports
|
||||||
|
|
||||||
|
And the best thing about is you don't need to do anything.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
If you are using markdown images you are good to go.
|
||||||
|
|
||||||
|
```md
|
||||||
|

|
||||||
|
```
|
||||||
|
|
||||||
|
will result in
|
||||||
|
|
||||||
|
```html
|
||||||
|
<picture>
|
||||||
|
<source
|
||||||
|
type="image/avif"
|
||||||
|
srcset="/images/5f03d82-300.avif 300w, /images/5f03d82-820.avif 820w"
|
||||||
|
sizes="(min-width: 1024px) 820px, calc(100vw - 20px)"
|
||||||
|
/>
|
||||||
|
<source
|
||||||
|
type="image/jpeg"
|
||||||
|
srcset="/images/5f03d82-300.jpeg 300w, /images/5f03d82-820.jpeg 820w"
|
||||||
|
sizes="(min-width: 1024px) 820px, calc(100vw - 20px)"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
alt="My Image"
|
||||||
|
rocket-image="responsive"
|
||||||
|
src="/images/5f03d82-300.jpeg"
|
||||||
|
width="300"
|
||||||
|
height="158"
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
</picture>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Benefits
|
||||||
|
|
||||||
|
The main benefit is that we can serve the correct size and optimal image format depending on the browser capabilities leading to optimal loading times on different systems.
|
||||||
|
|
||||||
|
- Smaller images for smaller screens
|
||||||
|
|
||||||
|
When providing `srcset` and `sizes` the browser can decide which image makes the most sense to download.
|
||||||
|
This will lead to much faster websites especially on mobile where smaller images can be served.
|
||||||
|
If you wanna know more check out [The anatomy of responsive images](https://jakearchibald.com/2015/anatomy-of-responsive-images/).
|
||||||
|
|
||||||
|
- Serve the best/smallest image format the browser understands
|
||||||
|
|
||||||
|
There are currently ~3 formats you may want to consider `avif`, `webp` and `jpg`. The improvements are huge [webp is ~30% and avif ~50%](https://www.ctrl.blog/entry/webp-avif-comparison.html) smaller then the original jpg.
|
||||||
|
|
||||||
|
## Adding a caption
|
||||||
|
|
||||||
|
If you want to describe your image in more detail you can add a caption
|
||||||
|
|
||||||
|
```md
|
||||||
|

|
||||||
|
```
|
||||||
|
|
||||||
|
will result in
|
||||||
|
|
||||||
|
```html
|
||||||
|
<figure>
|
||||||
|
<picture>
|
||||||
|
<!-- picture code the same as above -->
|
||||||
|
</picture>
|
||||||
|
<figcaption>My caption text</figcaption>
|
||||||
|
</figure>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adjusting options
|
||||||
|
|
||||||
|
Under the hood it is using [11ty/image](https://www.11ty.dev/docs/plugins/image/) and all it's options are available.
|
||||||
|
|
||||||
|
<inline-notification type="tip">
|
||||||
|
|
||||||
|
If you are using a layout preset like `@rocket/launch` then you probably don't want to touch/change these options as the preset will set it for you accordion to its layout needs.
|
||||||
|
|
||||||
|
The default preset for regular markdown content is available as `responsive`.
|
||||||
|
|
||||||
|
</inline-notification>
|
||||||
|
|
||||||
|
👉 `rocket.config.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
widths: [300, 820],
|
||||||
|
formats: ['avif', 'jpeg'],
|
||||||
|
sizes: '(min-width: 1024px) 820px, calc(100vw - 20px)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Defining your own presets
|
||||||
|
|
||||||
|
You can add your own image preset like so
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
imagePresets: {
|
||||||
|
'my-image-preset': {
|
||||||
|
widths: [30, 60],
|
||||||
|
formats: ['avif', 'jpeg'],
|
||||||
|
sizes: '(min-width: 1024px) 30px, 60px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Once that `imagePreset` is defined you can use it by adding it to any `img` tag.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<img src="./path/to/image.jpg" alt="my alt" rocket-image="my-image-preset" />
|
||||||
|
```
|
||||||
|
|
||||||
|
## How does it work?
|
||||||
|
|
||||||
|
1. Each markdown image `` gets rendered as `<img src="path/to/image.jpg" alt="my image" rocket-image="responsive">`
|
||||||
|
2. We parse the html output and process every image which has `rocket-image`
|
||||||
|
3. Get the image preset settings from the name e.g. `rocket-image="my-image-preset"` reads `imagePreset['my-image-preset']`
|
||||||
|
4. Pass the settings onto `@11ty/image` to generate the image sizes and formats
|
||||||
|
5. With the metadata we render the html
|
||||||
|
|
||||||
|
## Default Formats
|
||||||
|
|
||||||
|
An [image file format](https://en.wikipedia.org/wiki/Image_file_formats) is a way of storing common image formats. Each format varies in capabilities like compression algorithm, availability, progressive rendering, encode and decode time, ...
|
||||||
|
Ultimately newer formats are usually smaller while retaining image quality which leads to faster websites.
|
||||||
|
|
||||||
|
By default, we generate `avif` and `jpg` because
|
||||||
|
|
||||||
|
- we only want to generate two versions to limit CI time and html size
|
||||||
|
- `avif` is significantly smaller than `webp`
|
||||||
|
- `avif` is available in
|
||||||
|
- Chrome since August 2020
|
||||||
|
- Firefox since June 2021
|
||||||
|
- `jpg` as a fallback for Edge, Safari, IE11
|
||||||
|
- `webp` would only help a small percentage of Edge & Safari on macOS 11 (Big Sur) users
|
||||||
|
|
||||||
|
This leads to the following situation:
|
||||||
|
|
||||||
|
- Chrome, Firefox gets the small `avif`
|
||||||
|
- Edge, Safari, IE11 gets the bigger `jpg`
|
||||||
|
|
||||||
|
To learn more about `avif` take a look at [AVIF has landed](https://jakearchibald.com/2020/avif-has-landed/).
|
||||||
|
|
||||||
|
If you want to add `webp` (or replace `avif` with it) you can do so by setting the formats
|
||||||
|
|
||||||
|
👉 `rocket.config.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
formats: ['avif', 'webp', 'jpeg'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Default widths
|
||||||
|
|
||||||
|
In order to understand the need for having a single image in multiple resolutions we need to understand the our website is served to many different environments and each may come with its own specific device pixel ratio (DPR). The device pixel ratio is the ratio between physical pixels and logical pixels. For instance, the Galaxy S20 report a device pixel ratio of 3, because the physical linear resolution is triple the logical linear resolution.
|
||||||
|
|
||||||
|
Physical resolution: 1440 x 3200
|
||||||
|
Logical resolution: 480 x 1067
|
||||||
|
|
||||||
|
And 1440 / 480 = 3.
|
||||||
|
|
||||||
|
By default, we generate the following widths `600`, `900` and `1640` because
|
||||||
|
|
||||||
|
- we only want to generate a small amount of widths to limit CI time and service worker cache size
|
||||||
|
- `600` is good for mobile with DRP 2
|
||||||
|
- `900` is good for mobile with DRP 3 and desktop with DPR of 1
|
||||||
|
- `1640` is good for desktop with DPR of 2
|
||||||
|
|
||||||
|
If you want to add more widths you can add them to `widths`.
|
||||||
|
|
||||||
|
👉 `rocket.config.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
widths: [300, 600, 900, 1200, 1640],
|
||||||
|
sizes: '(min-width: 1024px) 820px, calc(100vw - 20px)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
<inline-notification type="tip">
|
||||||
|
|
||||||
|
As an end user in most cases you don't want to mess with this as a layout preset should set this for you. If you are building your own layout preset then be sure to set `widths` and `sizes` via `adjustImagePresets`
|
||||||
|
|
||||||
|
```js
|
||||||
|
export function myPreset() {
|
||||||
|
return {
|
||||||
|
adjustImagePresets: imagePresets => ({
|
||||||
|
...imagePresets,
|
||||||
|
responsive: {
|
||||||
|
...imagePresets.responsive,
|
||||||
|
widths: [600, 900, 1640],
|
||||||
|
sizes: '(min-width: 1024px) 820px, calc(100vw - 40px)',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</inline-notification>
|
||||||
|
|
||||||
|
```js script
|
||||||
|
import '@rocket/launch/inline-notification/inline-notification.js';
|
||||||
|
```
|
||||||
45
docs/docs/configuration/service-worker.md
Normal file
45
docs/docs/configuration/service-worker.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Configuration >> Service Worker ||30
|
||||||
|
|
||||||
|
Rocket does come with a default service worker that will
|
||||||
|
|
||||||
|
- cache already visited pages
|
||||||
|
- cache assets of visited pages (up to 100 files then it replaces older entries)
|
||||||
|
- reload the page if a newer html page version is available on service worker activation
|
||||||
|
|
||||||
|
## Adjusting the file name
|
||||||
|
|
||||||
|
Changing the service worker file name can be quite a hassle so you can adjust generate file name via a config.
|
||||||
|
|
||||||
|
👉 `rocket.config.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
serviceWorkerName: 'my-service-worker-name.js',
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Meet the Service Worker
|
||||||
|
|
||||||
|
The default service worker will work for many scenarios however your needs my vary.
|
||||||
|
To enable different service worker strategies you can replace the default service worker code by providing a file at `_assets/service-worker.js`.
|
||||||
|
This file will be auto transformed and generated in the root of the website using the defined `serviceWorkerName`.
|
||||||
|
|
||||||
|
For inspiration, you can take a look at the default config.
|
||||||
|
|
||||||
|
[https://github.com/modernweb-dev/rocket/blob/main/packages/cli/preset/\_assets/service-worker.js](https://github.com/modernweb-dev/rocket/blob/main/packages/cli/preset/_assets/service-worker.js)
|
||||||
|
|
||||||
|
Be sure to check out [workbox](https://developers.google.com/web/tools/workbox) for more service worker magic.
|
||||||
|
|
||||||
|
And if you wanna have a 30 minutes crash course we highly recommend the talk [Service Workers For The Rest Of Us](https://vimeo.com/362260166) by [Philip Walton](https://twitter.com/philwalton).
|
||||||
|
|
||||||
|
## Registration
|
||||||
|
|
||||||
|
The registration happens via another file that you can also overwrite at `_assets/scripts/registerServiceWorker.js`.
|
||||||
|
|
||||||
|
Below you find the default implementation.
|
||||||
|
|
||||||
|
<!-- prettier-ignore-start -->
|
||||||
|
```js
|
||||||
|
{{ '/_assets/scripts/registerServiceWorker.js' | asset | toAbsPath | inlineFilePath; }}
|
||||||
|
```
|
||||||
|
<!-- prettier-ignore-end -->
|
||||||
69
docs/docs/markdown-javascript/assets/demo-element.js
Normal file
69
docs/docs/markdown-javascript/assets/demo-element.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
class DemoElement extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.attachShadow({ mode: 'open' });
|
||||||
|
|
||||||
|
this.platform = 'the web';
|
||||||
|
this.language = 'en-US';
|
||||||
|
this.theme = 'light';
|
||||||
|
|
||||||
|
this.observer = new MutationObserver(this.updateData);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateData = () => {
|
||||||
|
this.platform = document.documentElement.getAttribute('platform') || 'the web';
|
||||||
|
this.language = document.documentElement.getAttribute('data-lang') || 'en-US';
|
||||||
|
this.theme = document.documentElement.getAttribute('theme') || 'light';
|
||||||
|
this.requestUpdate();
|
||||||
|
};
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.updateData();
|
||||||
|
|
||||||
|
this.observer.observe(document.documentElement, { attributes: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
requestUpdate() {
|
||||||
|
this.shadowRoot.innerHTML = this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return `
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
background: var(--demo-background-color);
|
||||||
|
color: var(--demo-color);
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host[platform~="web"] {
|
||||||
|
border-bottom: 2px solid #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 640px) {
|
||||||
|
.about {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.about ul {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<p>Hello I am DemoElement 👋</p>
|
||||||
|
<div class="about">
|
||||||
|
<ul>
|
||||||
|
<li>My purpose is to demonstrate how an element can adopt to different environments</li>
|
||||||
|
<li>I like <strong>${this.platform}</strong></li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>My mother languages is <strong>${this.language}</strong></li>
|
||||||
|
<li>I feel very comfortable in the <strong>${this.theme}</strong></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('demo-element', DemoElement);
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
# Markdown JavaScript >> Overview || 10
|
# Markdown JavaScript >> Overview || 10
|
||||||
|
|
||||||
|
```js script
|
||||||
|
import '@mdjs/mdjs-story/define';
|
||||||
|
import '@mdjs/mdjs-preview/define';
|
||||||
|
import { html } from '@mdjs/mdjs-story';
|
||||||
|
```
|
||||||
|
|
||||||
Markdown JavaScript (mdjs) is a format that allows you to use JavaScript with Markdown, to create interactive demos. It does so by "annotating" JavaScript that should be executed in Markdown.
|
Markdown JavaScript (mdjs) is a format that allows you to use JavaScript with Markdown, to create interactive demos. It does so by "annotating" JavaScript that should be executed in Markdown.
|
||||||
|
|
||||||
To annotate we use a code block with `js script`.
|
To annotate we use a code block with `js script`.
|
||||||
@@ -56,20 +62,13 @@ mdjs comes with some additional helpers you can choose to import:
|
|||||||
|
|
||||||
````md
|
````md
|
||||||
```js script
|
```js script
|
||||||
import '@mdjs/mdjs-story/mdjs-story.js';
|
import '@mdjs/mdjs-story/define';
|
||||||
import '@mdjs/mdjs-preview/mdjs-preview.js';
|
import '@mdjs/mdjs-preview/define';
|
||||||
```
|
```
|
||||||
````
|
````
|
||||||
|
|
||||||
Once loaded you can use them like so:
|
Once loaded you can use them like so:
|
||||||
|
|
||||||
````md
|
|
||||||
```js script
|
|
||||||
import '@mdjs/mdjs-story/mdjs-story.js';
|
|
||||||
import '@mdjs/mdjs-preview/mdjs-preview.js';
|
|
||||||
```
|
|
||||||
````
|
|
||||||
|
|
||||||
### Story
|
### Story
|
||||||
|
|
||||||
The code snippet will actually get executed at that place and you will have a live demo
|
The code snippet will actually get executed at that place and you will have a live demo
|
||||||
@@ -117,12 +116,6 @@ export const JsPreviewStory = () => html` <demo-wc-card>JS Preview Story</demo-w
|
|||||||
|
|
||||||
Here is a live example from [demo-wc-card](https://www.npmjs.com/package/demo-wc-card).
|
Here is a live example from [demo-wc-card](https://www.npmjs.com/package/demo-wc-card).
|
||||||
|
|
||||||
```js script
|
|
||||||
import '@mdjs/mdjs-story/mdjs-story.js';
|
|
||||||
import '@mdjs/mdjs-preview/mdjs-preview.js';
|
|
||||||
import { html } from 'lit-html';
|
|
||||||
```
|
|
||||||
|
|
||||||
```js preview-story
|
```js preview-story
|
||||||
import 'demo-wc-card/demo-wc-card.js';
|
import 'demo-wc-card/demo-wc-card.js';
|
||||||
export const header = () => {
|
export const header = () => {
|
||||||
@@ -132,31 +125,6 @@ export const header = () => {
|
|||||||
|
|
||||||
## Supported Systems
|
## Supported Systems
|
||||||
|
|
||||||
### es-dev-server
|
|
||||||
|
|
||||||
Preview your mdjs readme with live demos and auto reload.
|
|
||||||
|
|
||||||
- Add to your `package.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
"scripts": {
|
|
||||||
"start": "es-dev-server",
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- Create a `es-dev-server.config.js` in the root of your repository.
|
|
||||||
|
|
||||||
```js
|
|
||||||
const { mdjsTransformer } = require('@mdjs/core');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
nodeResolve: true,
|
|
||||||
open: 'README.md',
|
|
||||||
watch: true,
|
|
||||||
responseTransformers: [mdjsTransformer],
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Storybook
|
### Storybook
|
||||||
|
|
||||||
Please check out [@open-wc/demoing-storybook](https://open-wc.org/demoing/) for a fully integrated setup.
|
Please check out [@open-wc/demoing-storybook](https://open-wc.org/demoing/) for a fully integrated setup.
|
||||||
|
|||||||
@@ -2,18 +2,165 @@
|
|||||||
|
|
||||||
You can showcase live running code by annotating a code block with `js preview-story`.
|
You can showcase live running code by annotating a code block with `js preview-story`.
|
||||||
|
|
||||||
````md
|
## Features
|
||||||
```js preview-story
|
|
||||||
import { html } from 'lit-html';
|
|
||||||
|
|
||||||
export const foo = () => html` <p>my html</p> `;
|
- Shows components inside the page as they are
|
||||||
|
- You can enable “Simulation Mode” to break them out
|
||||||
|
- Simulation mode renders in an iframe to supporting media queries and isolated Simulation settings
|
||||||
|
- Simulation Settings
|
||||||
|
- Style (windows, mac, android, iOS)
|
||||||
|
- Size (small, medium, large, Galaxy S5, iPhone X, iPad …)
|
||||||
|
- Automatic Height
|
||||||
|
- Theme (light, dark)
|
||||||
|
- Language (en, nl, …)
|
||||||
|
- Settings are ”global” for all Simulators (e.g. changing one will change all)
|
||||||
|
- Settings can be remembered for other pages / return visits
|
||||||
|
|
||||||
|
```js script
|
||||||
|
import { html } from '@mdjs/mdjs-preview';
|
||||||
|
import './assets/demo-element.js';
|
||||||
|
```
|
||||||
|
|
||||||
|
## JavaScript Story
|
||||||
|
|
||||||
|
````md
|
||||||
|
```js script
|
||||||
|
import { html } from '@mdjs/mdjs-preview';
|
||||||
|
import './assets/demo-element.js';
|
||||||
|
```
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const foo = () => html`<demo-element></demo-element>`;
|
||||||
```
|
```
|
||||||
````
|
````
|
||||||
|
|
||||||
will result in
|
will result in
|
||||||
|
|
||||||
```js preview-story
|
```js preview-story
|
||||||
import { html } from 'lit-html';
|
export const foo = () => html` <demo-element></demo-element> `;
|
||||||
|
```
|
||||||
export const foo = () => html` <p>my html</p> `;
|
|
||||||
|
## HTML Story
|
||||||
|
|
||||||
|
````md
|
||||||
|
```html preview-story
|
||||||
|
<demo-element></demo-element>
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
will result in
|
||||||
|
|
||||||
|
```html preview-story
|
||||||
|
<demo-element></demo-element>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup Simulation Mode
|
||||||
|
|
||||||
|
For simulation mode we need a dedicated html file that will be used as an iframe target while loading stories.
|
||||||
|
|
||||||
|
The fastest way to create such a file is to use the `layout-simulator` layout.
|
||||||
|
|
||||||
|
Create a file `docs/simulator.md` with the following content.
|
||||||
|
|
||||||
|
```md
|
||||||
|
---
|
||||||
|
layout: layout-simulator
|
||||||
|
eleventyExcludeFromCollections: true
|
||||||
|
excludeFromSearch: true
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
Once you have that you need to configure it for the story renderer by setting it in your `rocket.config.js`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
setupUnifiedPlugins: [
|
||||||
|
adjustPluginOptions('mdjsSetupCode', {
|
||||||
|
simulationSettings: { simulatorUrl: '/simulator/' },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
<inline-notification type="tip">
|
||||||
|
|
||||||
|
You can freely choose the path for the "simulator" by creating the md file in a different folder and adjusting the path in the config.
|
||||||
|
|
||||||
|
</inline-notification>
|
||||||
|
|
||||||
|
## Simulator states
|
||||||
|
|
||||||
|
To simulate these stats that usually come from the device itself we put those infos on the document tag.
|
||||||
|
|
||||||
|
We can simulate the following settings
|
||||||
|
|
||||||
|
1. `platform`
|
||||||
|
Adopting styles and behavior depending on which device platform you are.
|
||||||
|
```html
|
||||||
|
<html platform="web"></html>
|
||||||
|
<html platform="android"></html>
|
||||||
|
<html platform="ios"></html>
|
||||||
|
<!-- potentially later -->
|
||||||
|
<html platform="web-windows"></html>
|
||||||
|
<html platform="web-mac"></html>
|
||||||
|
```
|
||||||
|
2. `theme`
|
||||||
|
Adjust your styles based on a theme - light/dark are the default but you can add as many as you want.
|
||||||
|
```html
|
||||||
|
<html theme="light"></html>
|
||||||
|
<html theme="dark"></html>
|
||||||
|
```
|
||||||
|
3. `language`
|
||||||
|
Best to relay on `data-lang` as `lang` often gets changes by translations services which may interfere with your translation loading system.
|
||||||
|
```html
|
||||||
|
<html lang="en-US" data-lang="en-US"></html>
|
||||||
|
<html lang="de-DE" data-lang="de-DE"></html>
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to react to such document changes you can use an [MutationObserver](https://developer.mozilla.org/de/docs/Web/API/MutationObserver).
|
||||||
|
|
||||||
|
For a vanilla web component it could look something like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
class DemoElement extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.attachShadow({ mode: 'open' });
|
||||||
|
|
||||||
|
this.platform = 'the web';
|
||||||
|
this.language = 'en-US';
|
||||||
|
this.theme = 'light';
|
||||||
|
|
||||||
|
this.observer = new MutationObserver(this.updateData);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateData = () => {
|
||||||
|
this.platform = document.documentElement.getAttribute('platform') || 'the web';
|
||||||
|
this.language = document.documentElement.getAttribute('data-lang') || 'en-US';
|
||||||
|
this.theme = document.documentElement.getAttribute('theme') || 'light';
|
||||||
|
this.requestUpdate();
|
||||||
|
};
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.updateData();
|
||||||
|
|
||||||
|
this.observer.observe(document.documentElement, { attributes: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
requestUpdate() {
|
||||||
|
this.shadowRoot.innerHTML = this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return `
|
||||||
|
...
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('demo-element', DemoElement);
|
||||||
|
```
|
||||||
|
|
||||||
|
```js script
|
||||||
|
import '@rocket/launch/inline-notification/inline-notification.js';
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -2,10 +2,16 @@
|
|||||||
|
|
||||||
You can showcase live running code by annotating a code block with `js story`.
|
You can showcase live running code by annotating a code block with `js story`.
|
||||||
|
|
||||||
````md
|
```js script
|
||||||
```js story
|
import { html } from '@mdjs/mdjs-story';
|
||||||
import { html } from 'lit-html';
|
```
|
||||||
|
|
||||||
|
````md
|
||||||
|
```js script
|
||||||
|
import { html } from '@mdjs/mdjs-story';
|
||||||
|
```
|
||||||
|
|
||||||
|
```js story
|
||||||
export const foo = () => html` <p>my html</p> `;
|
export const foo = () => html` <p>my html</p> `;
|
||||||
```
|
```
|
||||||
````
|
````
|
||||||
@@ -13,7 +19,5 @@ export const foo = () => html` <p>my html</p> `;
|
|||||||
will result in
|
will result in
|
||||||
|
|
||||||
```js story
|
```js story
|
||||||
import { html } from 'lit-html';
|
|
||||||
|
|
||||||
export const foo = () => html` <p>my html</p> `;
|
export const foo = () => html` <p>my html</p> `;
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ You write modern JavaScript using the latest browser features. Rollup will optim
|
|||||||
- Set HTML or JavaScript as input and/or output
|
- Set HTML or JavaScript as input and/or output
|
||||||
- Optimized for browsers which support modules
|
- Optimized for browsers which support modules
|
||||||
- Loads polyfills using feature detection
|
- Loads polyfills using feature detection
|
||||||
- Generates a service worker
|
|
||||||
- Minifies JavaScript
|
- Minifies JavaScript
|
||||||
- Minifies lit-html templates
|
- Minifies lit-html templates
|
||||||
|
|
||||||
|
|||||||
@@ -47,3 +47,9 @@ export const headlineConverter = () => html`
|
|||||||
```
|
```
|
||||||
|
|
||||||
How it then works is very similar to https://www.11ty.dev/docs/plugins/navigation/
|
How it then works is very similar to https://www.11ty.dev/docs/plugins/navigation/
|
||||||
|
|
||||||
|
## Sidebar redirects
|
||||||
|
|
||||||
|
By default, the sidebar nav redirects clicks on category headings to the first child page in that category.
|
||||||
|
|
||||||
|
To disable those redirects, override `_includes/_joiningBlocks/_layoutSidebar/sidebar/20-navigation.njk` and add the `no-redirects` attribute to the `<rocket-navigation>` element.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ For that reason Rocket creates those automatically with the title, parent title,
|
|||||||
|
|
||||||
It will look like this but with your logo:
|
It will look like this but with your logo:
|
||||||
|
|
||||||
<img src="{{ socialMediaImage }}" width="1200" height="630" alt="Social Media Image of this page" style="border: 1px solid #000" />
|
<img src="{{ socialMediaImage | url }}" width="1200" height="630" alt="Social Media Image of this page" style="border: 1px solid #000" />
|
||||||
|
|
||||||
There are multiple ways you can modify it.
|
There are multiple ways you can modify it.
|
||||||
|
|
||||||
|
|||||||
5
docs/simulator.md
Normal file
5
docs/simulator.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
layout: layout-simulator
|
||||||
|
eleventyExcludeFromCollections: true
|
||||||
|
excludeFromSearch: true
|
||||||
|
---
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@changesets/cli": "^2.12.0",
|
"@changesets/cli": "^2.12.0",
|
||||||
"@open-wc/testing": "^2.5.32",
|
"@open-wc/testing": "^3.0.0-next.1",
|
||||||
"@rollup/plugin-commonjs": "^17.0.0",
|
"@rollup/plugin-commonjs": "^17.0.0",
|
||||||
"@rollup/plugin-json": "^4.1.0",
|
"@rollup/plugin-json": "^4.1.0",
|
||||||
"@rollup/plugin-typescript": "^8.1.0",
|
"@rollup/plugin-typescript": "^8.1.0",
|
||||||
@@ -75,14 +75,14 @@
|
|||||||
"onchange": "^7.1.0",
|
"onchange": "^7.1.0",
|
||||||
"prettier": "^2.2.1",
|
"prettier": "^2.2.1",
|
||||||
"prettier-plugin-package": "^1.3.0",
|
"prettier-plugin-package": "^1.3.0",
|
||||||
"puppeteer": "^5.5.0",
|
"puppeteer": "^9.0.0",
|
||||||
"remark-emoji": "^2.1.0",
|
"remark-emoji": "^2.1.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rollup": "^2.36.1",
|
"rollup": "^2.36.1",
|
||||||
"rollup-plugin-terser": "^7.0.2",
|
"rollup-plugin-terser": "^7.0.2",
|
||||||
"sinon": "^9.2.3",
|
"sinon": "^9.2.3",
|
||||||
"ts-node": "^9.1.1",
|
"ts-node": "^9.1.1",
|
||||||
"typescript": "^4.1.3"
|
"typescript": "^4.3.2"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
|
|||||||
@@ -38,6 +38,6 @@
|
|||||||
"testing"
|
"testing"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"plugins-manager": "^0.2.0"
|
"plugins-manager": "^0.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
# @rocket/building-rollup
|
# @rocket/building-rollup
|
||||||
|
|
||||||
|
## 0.3.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 60e85a1: Support `picture` tags by handling `source` tags with `srcset` attributes in the rollup asset gathering build phase.
|
||||||
|
|
||||||
|
## 0.3.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 2724f07: Stop auto generating a service worker from a template. Setup your own and then bundle via `createServiceWorkerConfig`.
|
||||||
|
|
||||||
|
## 0.2.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- bad4686: Preserve attributes on script tags. Preserve export names.
|
||||||
|
|
||||||
## 0.1.3
|
## 0.1.3
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -6,3 +6,7 @@
|
|||||||
export { createBasicConfig, createBasicMetaConfig } from './src/createBasicConfig.js';
|
export { createBasicConfig, createBasicMetaConfig } from './src/createBasicConfig.js';
|
||||||
export { createSpaConfig, createSpaMetaConfig } from './src/createSpaConfig.js';
|
export { createSpaConfig, createSpaMetaConfig } from './src/createSpaConfig.js';
|
||||||
export { createMpaConfig, createMpaMetaConfig } from './src/createMpaConfig.js';
|
export { createMpaConfig, createMpaMetaConfig } from './src/createMpaConfig.js';
|
||||||
|
export {
|
||||||
|
createServiceWorkerConfig,
|
||||||
|
createServiceWorkerMetaConfig,
|
||||||
|
} from './src/createServiceWorkerConfig.js';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rocket/building-rollup",
|
"name": "@rocket/building-rollup",
|
||||||
"version": "0.1.3",
|
"version": "0.3.1",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
},
|
},
|
||||||
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
||||||
"homepage": "https://rocket.modern-web.dev/docs/tools/building-rollup/",
|
"homepage": "https://rocket.modern-web.dev/docs/tools/building-rollup/",
|
||||||
"type": "module",
|
|
||||||
"main": "./index.js",
|
"main": "./index.js",
|
||||||
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./index.js"
|
".": "./index.js"
|
||||||
},
|
},
|
||||||
@@ -55,11 +55,16 @@
|
|||||||
"@babel/preset-env": "^7.12.11",
|
"@babel/preset-env": "^7.12.11",
|
||||||
"@rollup/plugin-babel": "^5.2.2",
|
"@rollup/plugin-babel": "^5.2.2",
|
||||||
"@rollup/plugin-node-resolve": "^11.0.1",
|
"@rollup/plugin-node-resolve": "^11.0.1",
|
||||||
"@web/rollup-plugin-html": "^1.4.0",
|
"@rollup/plugin-replace": "^2.4.2",
|
||||||
|
"@web/rollup-plugin-html": "^1.8.0",
|
||||||
"@web/rollup-plugin-import-meta-assets": "^1.0.4",
|
"@web/rollup-plugin-import-meta-assets": "^1.0.4",
|
||||||
"@web/rollup-plugin-polyfills-loader": "^1.0.3",
|
"@web/rollup-plugin-polyfills-loader": "^1.1.0",
|
||||||
"browserslist": "^4.16.1",
|
"browserslist": "^4.16.1",
|
||||||
"rollup-plugin-terser": "^7.0.2",
|
"rollup-plugin-terser": "^7.0.2",
|
||||||
"rollup-plugin-workbox": "^6.1.0"
|
"workbox-broadcast-update": "^6.1.5",
|
||||||
|
"workbox-cacheable-response": "^6.1.5",
|
||||||
|
"workbox-expiration": "^6.1.5",
|
||||||
|
"workbox-routing": "^6.1.5",
|
||||||
|
"workbox-strategies": "^6.1.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export function createBasicMetaConfig(userConfig = { output: {} }) {
|
|||||||
const assetName = `[${developmentMode ? 'name' : 'hash'}][extname]`;
|
const assetName = `[${developmentMode ? 'name' : 'hash'}][extname]`;
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
preserveEntrySignatures: false,
|
preserveEntrySignatures: 'strict',
|
||||||
treeshake: !developmentMode,
|
treeshake: !developmentMode,
|
||||||
setupPlugins: [],
|
setupPlugins: [],
|
||||||
...userConfig,
|
...userConfig,
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ export function createMpaMetaConfig(userConfig = { output: {}, setupPlugins: []
|
|||||||
adjustPluginOptions('html', {
|
adjustPluginOptions('html', {
|
||||||
flattenOutput: false,
|
flattenOutput: false,
|
||||||
}),
|
}),
|
||||||
adjustPluginOptions('workbox', config => {
|
|
||||||
delete config.navigateFallback;
|
|
||||||
return config;
|
|
||||||
}),
|
|
||||||
...config.setupPlugins,
|
...config.setupPlugins,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
91
packages/building-rollup/src/createServiceWorkerConfig.js
Normal file
91
packages/building-rollup/src/createServiceWorkerConfig.js
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
|
import { terser } from 'rollup-plugin-terser';
|
||||||
|
import babelPkg from '@rollup/plugin-babel';
|
||||||
|
import replace from '@rollup/plugin-replace';
|
||||||
|
|
||||||
|
import { metaConfigToRollupConfig } from 'plugins-manager';
|
||||||
|
|
||||||
|
const { babel } = babelPkg;
|
||||||
|
|
||||||
|
export function createServiceWorkerConfig(userConfig) {
|
||||||
|
const { config, metaPlugins } = createServiceWorkerMetaConfig(userConfig);
|
||||||
|
return metaConfigToRollupConfig(config, metaPlugins);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createServiceWorkerMetaConfig(userConfig = { output: {} }) {
|
||||||
|
const developmentMode =
|
||||||
|
typeof userConfig.developmentMode !== undefined
|
||||||
|
? userConfig.developmentMode
|
||||||
|
: !!process.env.ROLLUP_WATCH;
|
||||||
|
delete userConfig.developmentMode;
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
treeshake: !developmentMode,
|
||||||
|
setupPlugins: [],
|
||||||
|
...userConfig,
|
||||||
|
|
||||||
|
output: {
|
||||||
|
format: 'iife',
|
||||||
|
file: 'service-worker.js',
|
||||||
|
...userConfig.output,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let metaPlugins = [
|
||||||
|
{
|
||||||
|
name: 'node-resolve',
|
||||||
|
plugin: resolve,
|
||||||
|
options: {
|
||||||
|
moduleDirectories: ['node_modules', 'web_modules'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'replace',
|
||||||
|
plugin: replace,
|
||||||
|
options: {
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(developmentMode ? 'development' : 'production'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'babel',
|
||||||
|
plugin: babel,
|
||||||
|
options: {
|
||||||
|
babelHelpers: 'bundled',
|
||||||
|
compact: true,
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
'@babel/preset-env',
|
||||||
|
{
|
||||||
|
targets: [
|
||||||
|
'last 3 Chrome major versions',
|
||||||
|
'last 3 ChromeAndroid major versions',
|
||||||
|
'last 3 Firefox major versions',
|
||||||
|
'last 3 Edge major versions',
|
||||||
|
'last 3 Safari major versions',
|
||||||
|
'last 3 iOS major versions',
|
||||||
|
],
|
||||||
|
useBuiltIns: false,
|
||||||
|
shippedProposals: true,
|
||||||
|
modules: false,
|
||||||
|
bugfixes: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'terser',
|
||||||
|
plugin: terser,
|
||||||
|
options: {
|
||||||
|
mangle: {
|
||||||
|
toplevel: true,
|
||||||
|
properties: {
|
||||||
|
regex: /(^_|_$)/,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return { config, metaPlugins, developmentMode };
|
||||||
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
import path from 'path';
|
|
||||||
import { rollupPluginHTML } from '@web/rollup-plugin-html';
|
import { rollupPluginHTML } from '@web/rollup-plugin-html';
|
||||||
import { generateSW } from 'rollup-plugin-workbox';
|
|
||||||
import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets';
|
import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets';
|
||||||
import { polyfillsLoader } from '@web/rollup-plugin-polyfills-loader';
|
import { polyfillsLoader } from '@web/rollup-plugin-polyfills-loader';
|
||||||
import { metaConfigToRollupConfig } from 'plugins-manager';
|
import { metaConfigToRollupConfig } from 'plugins-manager';
|
||||||
@@ -37,31 +35,6 @@ export function createSpaMetaConfig(userConfig = { output: {} }) {
|
|||||||
options: {
|
options: {
|
||||||
rootDir,
|
rootDir,
|
||||||
absoluteBaseUrl,
|
absoluteBaseUrl,
|
||||||
injectServiceWorker: true,
|
|
||||||
serviceWorkerPath: path.join(config.output.dir, 'service-worker.js'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'workbox',
|
|
||||||
plugin: generateSW,
|
|
||||||
options: {
|
|
||||||
// Keep 'legacy-*.js' just for retro compatibility
|
|
||||||
globIgnores: ['polyfills/*.js', 'legacy-*.js', 'nomodule-*.js'],
|
|
||||||
navigateFallback: '/index.html',
|
|
||||||
// where to output the generated sw
|
|
||||||
swDest: path.join(config.output.dir, 'service-worker.js'),
|
|
||||||
// directory to match patterns against to be precached
|
|
||||||
globDirectory: path.join(config.output.dir),
|
|
||||||
// cache any html js and css by default
|
|
||||||
globPatterns: ['**/*.{html,js,css,webmanifest}', '**/*-search-index.json'],
|
|
||||||
skipWaiting: true,
|
|
||||||
clientsClaim: true,
|
|
||||||
runtimeCaching: [
|
|
||||||
{
|
|
||||||
urlPattern: 'polyfills/*.js',
|
|
||||||
handler: 'CacheFirst',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ describe('plugin count', () => {
|
|||||||
expect(config.plugins.length).to.equal(3);
|
expect(config.plugins.length).to.equal(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('createSpaConfig has 7 plugins', () => {
|
it('createSpaConfig has 6 plugins', () => {
|
||||||
const config = createSpaConfig();
|
const config = createSpaConfig();
|
||||||
expect(config.plugins.length).to.equal(7);
|
expect(config.plugins.length).to.equal(6);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('createMpaConfig has 7 plugins', () => {
|
it('createMpaConfig has 6 plugins', () => {
|
||||||
const config = createMpaConfig();
|
const config = createMpaConfig();
|
||||||
expect(config.plugins.length).to.equal(7);
|
expect(config.plugins.length).to.equal(6);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,10 +26,7 @@ async function execute(configString) {
|
|||||||
const config = (await import(configPath)).default;
|
const config = (await import(configPath)).default;
|
||||||
await buildAndWrite(config);
|
await buildAndWrite(config);
|
||||||
|
|
||||||
return async (
|
return async (fileName, { stripToBody = false, stripStartEndWhitespace = true } = {}) => {
|
||||||
fileName,
|
|
||||||
{ stripServiceWorker = false, stripToBody = false, stripStartEndWhitespace = true } = {},
|
|
||||||
) => {
|
|
||||||
let text = await fs.promises.readFile(
|
let text = await fs.promises.readFile(
|
||||||
path.join(config.output.dir, fileName.split('/').join(path.sep)),
|
path.join(config.output.dir, fileName.split('/').join(path.sep)),
|
||||||
);
|
);
|
||||||
@@ -39,11 +36,6 @@ async function execute(configString) {
|
|||||||
const bodyCloseTagStart = text.indexOf('</body>');
|
const bodyCloseTagStart = text.indexOf('</body>');
|
||||||
text = text.substring(bodyOpenTagEnd, bodyCloseTagStart);
|
text = text.substring(bodyOpenTagEnd, bodyCloseTagStart);
|
||||||
}
|
}
|
||||||
if (stripServiceWorker) {
|
|
||||||
const scriptOpenTagEnd = text.indexOf('<script inject-service-worker');
|
|
||||||
const scriptCloseTagStart = text.indexOf('</script>', scriptOpenTagEnd) + 9;
|
|
||||||
text = text.substring(0, scriptOpenTagEnd) + text.substring(scriptCloseTagStart);
|
|
||||||
}
|
|
||||||
if (stripStartEndWhitespace) {
|
if (stripStartEndWhitespace) {
|
||||||
text = text.trim();
|
text = text.trim();
|
||||||
}
|
}
|
||||||
@@ -57,25 +49,26 @@ describe('createMapConfig', () => {
|
|||||||
|
|
||||||
const indexHtml = await readOutput('index.html', {
|
const indexHtml = await readOutput('index.html', {
|
||||||
stripToBody: true,
|
stripToBody: true,
|
||||||
stripServiceWorker: true,
|
|
||||||
});
|
});
|
||||||
expect(indexHtml).to.equal('<h1>Only static HTML content in index.html</h1>');
|
expect(indexHtml).to.equal('<h1>Only static HTML content in index.html</h1>');
|
||||||
|
|
||||||
const subHtmlIndexHtml = await readOutput('sub-html/index.html', {
|
const subHtmlIndexHtml = await readOutput('sub-html/index.html', {
|
||||||
stripToBody: true,
|
stripToBody: true,
|
||||||
stripServiceWorker: true,
|
|
||||||
});
|
});
|
||||||
expect(subHtmlIndexHtml).to.equal('<h1>Only static HTML content in sub-html/index.html</h1>');
|
expect(subHtmlIndexHtml).to.equal('<h1>Only static HTML content in sub-html/index.html</h1>');
|
||||||
|
|
||||||
const subJsIndexHtml = await readOutput('sub-js/index.html', {
|
const subJsIndexHtml = await readOutput('sub-js/index.html', {
|
||||||
stripToBody: true,
|
stripToBody: true,
|
||||||
stripServiceWorker: true,
|
|
||||||
});
|
});
|
||||||
expect(subJsIndexHtml).to.equal(
|
expect(subJsIndexHtml).to.equal(
|
||||||
'<h1>Has js in sub-js/index.html</h1>\n\n\n<script type="module" src="../sub-js.js"></script>',
|
'<h1>Has js in sub-js/index.html</h1>\n\n\n<script type="module" src="../sub-js.js"></script>',
|
||||||
);
|
);
|
||||||
|
|
||||||
const serviceWorkerJs = await readOutput('service-worker.js');
|
const subJsAbsoluteIndexHtml = await readOutput('sub-js-absolute/index.html', {
|
||||||
expect(serviceWorkerJs).to.include('Promise'); // not empty string might be enough...
|
stripToBody: true,
|
||||||
|
});
|
||||||
|
expect(subJsAbsoluteIndexHtml).to.equal(
|
||||||
|
'<h1>Has js in sub-js-absolute/index.html</h1>\n\n\n<script type="module" src="../sub-js-absolute.js"></script>',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<h1>Has js in sub-js-absolute/index.html</h1>
|
||||||
|
<script type="module" src="/sub-js-absolute/sub-js-absolute.js"></script>
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
# check-html-links
|
# check-html-links
|
||||||
|
|
||||||
|
## 0.2.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 66c2d78: fix: windows path issue
|
||||||
|
|
||||||
## 0.2.1
|
## 0.2.1
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "check-html-links",
|
"name": "check-html-links",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
@@ -13,11 +13,11 @@
|
|||||||
},
|
},
|
||||||
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
||||||
"homepage": "https://rocket.modern-web.dev/docs/tools/check-html-links/",
|
"homepage": "https://rocket.modern-web.dev/docs/tools/check-html-links/",
|
||||||
|
"main": "./index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"check-html-links": "src/cli.js"
|
"check-html-links": "src/cli.js"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./index.js",
|
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./index.js"
|
".": "./index.js"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { createRequire } from 'module';
|
|||||||
|
|
||||||
import { listFiles } from './listFiles.js';
|
import { listFiles } from './listFiles.js';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import slash from 'slash';
|
||||||
|
|
||||||
/** @typedef {import('../types/main').Link} Link */
|
/** @typedef {import('../types/main').Link} Link */
|
||||||
/** @typedef {import('../types/main').LocalFile} LocalFile */
|
/** @typedef {import('../types/main').LocalFile} LocalFile */
|
||||||
@@ -45,7 +46,7 @@ function extractReferences(htmlFilePath) {
|
|||||||
if (ev === SaxEventType.Attribute) {
|
if (ev === SaxEventType.Attribute) {
|
||||||
const data = /** @type {Attribute} */ (/** @type {any} */ (_data));
|
const data = /** @type {Attribute} */ (/** @type {any} */ (_data));
|
||||||
const attributeName = data.name.toString();
|
const attributeName = data.name.toString();
|
||||||
const value = data.value.toString();
|
const value = slash(data.value.toString());
|
||||||
const entry = {
|
const entry = {
|
||||||
attribute: attributeName,
|
attribute: attributeName,
|
||||||
value,
|
value,
|
||||||
|
|||||||
@@ -1,5 +1,90 @@
|
|||||||
# @rocket/cli
|
# @rocket/cli
|
||||||
|
|
||||||
|
## 0.9.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- eae2007: Update to mdjs version that uses lit 2 and renders stories to light dom
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [eae2007]
|
||||||
|
- @rocket/eleventy-plugin-mdjs-unified@0.5.0
|
||||||
|
|
||||||
|
## 0.8.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 60e85a1: Support `picture` tags by handling `source` tags with `srcset` attributes in the rollup asset gathering build phase.
|
||||||
|
- Updated dependencies [60e85a1]
|
||||||
|
- @rocket/building-rollup@0.3.1
|
||||||
|
|
||||||
|
## 0.8.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- c338696: Updated dependency of eleventy-img for M1 compatibility
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 8bba4a8: Every content image in markdown will outputted in multiple widths and formats to ensure small image file sizes while retaining quality.
|
||||||
|
You can adjust the defaults by setting `imagePresets.responsive`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
widths: [600, 900, 1640],
|
||||||
|
formats: ['avif', 'jpeg'],
|
||||||
|
sizes: '(min-width: 1024px) 820px, calc(100vw - 40px)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 0.7.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 2724f07: The service worker no longer precaches all urls and assets. It now
|
||||||
|
|
||||||
|
- caches already visited pages
|
||||||
|
- caches assets of visited pages (up to 100 files then it replaces older entries)
|
||||||
|
- on service worker activation it will reload the page if a newer version is available
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [2724f07]
|
||||||
|
- @rocket/building-rollup@0.3.0
|
||||||
|
|
||||||
|
## 0.6.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 2b7f1ee: Add support for pathprefix
|
||||||
|
- Updated dependencies [2b7f1ee]
|
||||||
|
- @rocket/eleventy-plugin-mdjs-unified@0.4.1
|
||||||
|
|
||||||
|
## 0.6.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- ed86ff2: Do not set `data-localize-lang` in the simulator iframe html tag
|
||||||
|
- f4a0ab5: Pass document shadowRoot to iframe
|
||||||
|
- c675820: fix: windows path issue avoid filtering of index section of collections
|
||||||
|
|
||||||
|
## 0.6.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- abc8a02: You can now use an absolute path for the rootDir
|
||||||
|
- Updated dependencies [bad4686]
|
||||||
|
- Updated dependencies [2267e72]
|
||||||
|
- @rocket/building-rollup@0.2.0
|
||||||
|
- @rocket/eleventy-plugin-mdjs-unified@0.4.0
|
||||||
|
|
||||||
## 0.6.0
|
## 0.6.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rocket/cli",
|
"name": "@rocket/cli",
|
||||||
"version": "0.6.0",
|
"version": "0.9.0",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
@@ -13,11 +13,11 @@
|
|||||||
},
|
},
|
||||||
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
||||||
"homepage": "https://rocket.modern-web.dev/",
|
"homepage": "https://rocket.modern-web.dev/",
|
||||||
|
"main": "./index.cjs",
|
||||||
"bin": {
|
"bin": {
|
||||||
"rocket": "src/cli.js"
|
"rocket": "src/cli.js"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./index.cjs",
|
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"require": "./index.cjs",
|
"require": "./index.cjs",
|
||||||
@@ -56,10 +56,10 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@11ty/eleventy": "^0.11.1",
|
"@11ty/eleventy": "^0.11.1",
|
||||||
"@11ty/eleventy-img": "^0.7.4",
|
"@11ty/eleventy-img": "^0.9.0",
|
||||||
"@rocket/building-rollup": "^0.1.3",
|
"@rocket/building-rollup": "^0.3.1",
|
||||||
"@rocket/core": "^0.1.2",
|
"@rocket/core": "^0.1.2",
|
||||||
"@rocket/eleventy-plugin-mdjs-unified": "^0.3.1",
|
"@rocket/eleventy-plugin-mdjs-unified": "^0.5.0",
|
||||||
"@rocket/eleventy-rocket-nav": "^0.3.0",
|
"@rocket/eleventy-rocket-nav": "^0.3.0",
|
||||||
"@rollup/plugin-babel": "^5.2.2",
|
"@rollup/plugin-babel": "^5.2.2",
|
||||||
"@rollup/plugin-node-resolve": "^11.0.1",
|
"@rollup/plugin-node-resolve": "^11.0.1",
|
||||||
@@ -67,13 +67,15 @@
|
|||||||
"@web/dev-server": "^0.1.4",
|
"@web/dev-server": "^0.1.4",
|
||||||
"@web/dev-server-rollup": "^0.3.2",
|
"@web/dev-server-rollup": "^0.3.2",
|
||||||
"@web/rollup-plugin-copy": "^0.2.0",
|
"@web/rollup-plugin-copy": "^0.2.0",
|
||||||
"check-html-links": "^0.2.1",
|
"check-html-links": "^0.2.2",
|
||||||
"command-line-args": "^5.1.1",
|
"command-line-args": "^5.1.1",
|
||||||
"command-line-usage": "^6.1.1",
|
"command-line-usage": "^6.1.1",
|
||||||
"fs-extra": "^9.0.1",
|
"fs-extra": "^9.0.1",
|
||||||
"micromatch": "^4.0.2",
|
"micromatch": "^4.0.2",
|
||||||
"plugins-manager": "^0.2.1",
|
"plugins-manager": "^0.2.2",
|
||||||
"utf8": "^3.0.0"
|
"slash": "^3.0.0",
|
||||||
|
"utf8": "^3.0.0",
|
||||||
|
"workbox-window": "^6.1.5"
|
||||||
},
|
},
|
||||||
"types": "dist-types/index.d.ts"
|
"types": "dist-types/index.d.ts"
|
||||||
}
|
}
|
||||||
|
|||||||
22
packages/cli/preset/_assets/scripts/registerServiceWorker.js
Normal file
22
packages/cli/preset/_assets/scripts/registerServiceWorker.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
(async () => {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
const { Workbox } = await import('workbox-window');
|
||||||
|
|
||||||
|
const url = window.__rocketServiceWorkerUrl || '/service-worker.js';
|
||||||
|
const wb = new Workbox(url);
|
||||||
|
wb.addEventListener('message', event => {
|
||||||
|
if (event.data.type === 'CACHE_UPDATED') {
|
||||||
|
const { updatedURL } = event.data.payload;
|
||||||
|
console.log(`Reloading as a newer version of ${updatedURL} became available!`);
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
wb.register()
|
||||||
|
.then(function () {
|
||||||
|
console.log('ServiceWorker registered.');
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
console.log('ServiceWorker registration failed: ', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
29
packages/cli/preset/_assets/service-worker.js
Normal file
29
packages/cli/preset/_assets/service-worker.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { registerRoute } from 'workbox-routing';
|
||||||
|
import { CacheFirst, StaleWhileRevalidate } from 'workbox-strategies';
|
||||||
|
import { BroadcastUpdatePlugin } from 'workbox-broadcast-update';
|
||||||
|
import { ExpirationPlugin } from 'workbox-expiration';
|
||||||
|
|
||||||
|
addEventListener('install', () => {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
skipWaiting();
|
||||||
|
});
|
||||||
|
|
||||||
|
// addEventListener('activate', () => {
|
||||||
|
// console.log('activate');
|
||||||
|
// });
|
||||||
|
|
||||||
|
const cacheFirst = new CacheFirst({
|
||||||
|
cacheName: 'assets',
|
||||||
|
plugins: [
|
||||||
|
new ExpirationPlugin({
|
||||||
|
maxEntries: 100,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const staleWhileRevalidate = new StaleWhileRevalidate({
|
||||||
|
cacheName: 'pages',
|
||||||
|
plugins: [new BroadcastUpdatePlugin()],
|
||||||
|
});
|
||||||
|
|
||||||
|
registerRoute(/(\/|\.html)$/, staleWhileRevalidate);
|
||||||
|
registerRoute(/\.(css|m?js|svg|woff2|png|jpg|gif|json|xml)$/, cacheFirst);
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
window.__rocketServiceWorkerUrl = '/{{ rocketConfig.serviceWorkerName }}';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="module" inject-service-worker="" src="{{ '/_assets/scripts/registerServiceWorker.js' | asset | url }}"></script>
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<script>
|
|
||||||
{{ '_assets/_inline-scripts/serviceWorkerUpdate.js' | asset | toAbsPath | inlineFilePath | safe }}
|
|
||||||
</script>
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<meta property="og:site_name" content="{{ site.name }}"/>
|
<meta property="og:site_name" content="{{ site.name }}"/>
|
||||||
<meta property="og:type" content="website"/>
|
<meta property="og:type" content="website"/>
|
||||||
|
|
||||||
<meta property="og:image" content="{{ socialMediaImage }}"/>
|
<meta property="og:image" content="{{ socialMediaImage | url }}"/>
|
||||||
<meta property="og:url" content="{{ page.url }}"/>
|
<meta property="og:url" content="{{ page.url | url }}"/>
|
||||||
|
|
||||||
<meta name="twitter:card" content="summary_large_image"/>
|
<meta name="twitter:card" content="summary_large_image"/>
|
||||||
|
|||||||
69
packages/cli/preset/_includes/layout-simulator.njk
Normal file
69
packages/cli/preset/_includes/layout-simulator.njk
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<html theme="light" platform="web" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
height: fit-content;
|
||||||
|
}
|
||||||
|
html[edge-distance] body {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="module">
|
||||||
|
import { render } from '@mdjs/mdjs-story';
|
||||||
|
|
||||||
|
async function onHashChange() {
|
||||||
|
const urlParts = new URLSearchParams(document.location.hash.substr(1));
|
||||||
|
|
||||||
|
if (urlParts.get('stylesheets')) {
|
||||||
|
for (const stylesheet of urlParts.getAll('stylesheets')) {
|
||||||
|
if (!document.querySelector(`link[rel="stylesheet"][href="${stylesheet}"]`)) {
|
||||||
|
const link = document.createElement('link');
|
||||||
|
link.rel = 'stylesheet';
|
||||||
|
link.href = stylesheet;
|
||||||
|
document.head.appendChild(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (urlParts.get('theme')) {
|
||||||
|
document.documentElement.setAttribute('theme', urlParts.get('theme'));
|
||||||
|
}
|
||||||
|
if (urlParts.get('platform')) {
|
||||||
|
document.documentElement.setAttribute('platform', urlParts.get('platform'));
|
||||||
|
}
|
||||||
|
if (urlParts.get('language')) {
|
||||||
|
document.documentElement.setAttribute('lang', urlParts.get('language'));
|
||||||
|
document.documentElement.setAttribute('data-lang', urlParts.get('language'));
|
||||||
|
}
|
||||||
|
if (urlParts.get('story-key')) {
|
||||||
|
document.documentElement.setAttribute('story-key', urlParts.get('story-key'));
|
||||||
|
}
|
||||||
|
if (urlParts.get('edge-distance') === 'true') {
|
||||||
|
document.documentElement.setAttribute('edge-distance', '');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('edge-distance');
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = await import(urlParts.get('story-file'));
|
||||||
|
render(mod[urlParts.get('story-key')]({ shadowRoot: document }), document.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('hashchange', onHashChange, false);
|
||||||
|
onHashChange();
|
||||||
|
|
||||||
|
const observer = new ResizeObserver(() => {
|
||||||
|
const dimensions = document.body.getBoundingClientRect();
|
||||||
|
const data = {
|
||||||
|
action: 'mdjs-viewer-resize',
|
||||||
|
storyKey: document.documentElement.getAttribute('story-key'),
|
||||||
|
width: dimensions.width,
|
||||||
|
height: dimensions.height,
|
||||||
|
};
|
||||||
|
parent.postMessage(JSON.stringify(data), '*');
|
||||||
|
});
|
||||||
|
observer.observe(document.body);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
||||||
@@ -3,9 +3,10 @@
|
|||||||
|
|
||||||
import { rollup } from 'rollup';
|
import { rollup } from 'rollup';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
import { copy } from '@web/rollup-plugin-copy';
|
import { copy } from '@web/rollup-plugin-copy';
|
||||||
|
|
||||||
import { createMpaConfig } from '@rocket/building-rollup';
|
import { createMpaConfig, createServiceWorkerConfig } from '@rocket/building-rollup';
|
||||||
import { addPlugin, adjustPluginOptions } from 'plugins-manager';
|
import { addPlugin, adjustPluginOptions } from 'plugins-manager';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,7 +46,7 @@ async function productionBuild(config) {
|
|||||||
dir: config.outputDir,
|
dir: config.outputDir,
|
||||||
},
|
},
|
||||||
// custom
|
// custom
|
||||||
rootDir: config.outputDevDir,
|
rootDir: path.resolve(config.outputDevDir),
|
||||||
absoluteBaseUrl: config.absoluteBaseUrl,
|
absoluteBaseUrl: config.absoluteBaseUrl,
|
||||||
setupPlugins: [
|
setupPlugins: [
|
||||||
...defaultSetupPlugins,
|
...defaultSetupPlugins,
|
||||||
@@ -55,6 +56,18 @@ async function productionBuild(config) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await buildAndWrite(mpaConfig);
|
await buildAndWrite(mpaConfig);
|
||||||
|
|
||||||
|
const serviceWorkerSourcePath = path.resolve('docs/_merged_assets/service-worker.js');
|
||||||
|
if (fs.existsSync(serviceWorkerSourcePath)) {
|
||||||
|
const serviceWorkerConfig = createServiceWorkerConfig({
|
||||||
|
input: serviceWorkerSourcePath,
|
||||||
|
output: {
|
||||||
|
file: path.join(path.resolve(config.outputDir), config.serviceWorkerName),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await buildAndWrite(serviceWorkerConfig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RocketBuild {
|
export class RocketBuild {
|
||||||
|
|||||||
244
packages/cli/src/eleventy-plugins/insertResponsiveImages.cjs
Normal file
244
packages/cli/src/eleventy-plugins/insertResponsiveImages.cjs
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const EleventyImage = require('@11ty/eleventy-img');
|
||||||
|
const { SaxEventType, SAXParser } = require('sax-wasm');
|
||||||
|
const { getComputedConfig } = require('../public/computedConfig.cjs');
|
||||||
|
|
||||||
|
const saxPath = require.resolve('sax-wasm/lib/sax-wasm.wasm');
|
||||||
|
const saxWasmBuffer = fs.readFileSync(saxPath);
|
||||||
|
|
||||||
|
/** @typedef {import('../types').Heading} Heading */
|
||||||
|
|
||||||
|
/** @typedef {import('sax-wasm').Text} Text */
|
||||||
|
/** @typedef {import('sax-wasm').Tag} Tag */
|
||||||
|
/** @typedef {import('sax-wasm').Position} Position */
|
||||||
|
|
||||||
|
// Instantiate
|
||||||
|
const parser = new SAXParser(
|
||||||
|
SaxEventType.CloseTag,
|
||||||
|
{ highWaterMark: 256 * 1024 }, // 256k chunks
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} options
|
||||||
|
* @param {string} options.html
|
||||||
|
* @param {Position} options.start
|
||||||
|
* @param {Position} options.end
|
||||||
|
* @param {string} options.insert
|
||||||
|
*/
|
||||||
|
function replaceBetween({ html, start, end, insert = '' }) {
|
||||||
|
const lines = html.split('\n');
|
||||||
|
const i = start.line;
|
||||||
|
const line = lines[i];
|
||||||
|
const upToChange = line.slice(0, start.character);
|
||||||
|
const afterChange = line.slice(end.character - 4);
|
||||||
|
|
||||||
|
lines[i] = `${upToChange}${insert}${afterChange}`;
|
||||||
|
return lines.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Tag} data
|
||||||
|
* @param {string} name
|
||||||
|
*/
|
||||||
|
function getAttribute(data, name) {
|
||||||
|
if (data.attributes) {
|
||||||
|
const { attributes } = data;
|
||||||
|
const foundIndex = attributes.findIndex(entry => entry.name.value === name);
|
||||||
|
if (foundIndex !== -1) {
|
||||||
|
return attributes[foundIndex].value.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Tag} data
|
||||||
|
*/
|
||||||
|
function getAttributes(data) {
|
||||||
|
if (data.attributes) {
|
||||||
|
const { attributes } = data;
|
||||||
|
return attributes.map(entry => ({ name: entry.name.value, value: entry.value.value }));
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @param {Tag} data
|
||||||
|
// */
|
||||||
|
// function getText(data) {
|
||||||
|
// if (data.textNodes) {
|
||||||
|
// return data.textNodes.map(textNode => textNode.value).join('');
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @param {Tag} data
|
||||||
|
// */
|
||||||
|
// function getClassList(data) {
|
||||||
|
// const classString = getAttribute(data, 'class');
|
||||||
|
// return classString ? classString.split(' ') : [];
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} html
|
||||||
|
*/
|
||||||
|
function getImages(html) {
|
||||||
|
/** @type {Heading[]} */
|
||||||
|
const images = [];
|
||||||
|
parser.eventHandler = (ev, _data) => {
|
||||||
|
if (ev === SaxEventType.CloseTag) {
|
||||||
|
const data = /** @type {Tag} */ (/** @type {any} */ (_data));
|
||||||
|
if (data.name === 'img') {
|
||||||
|
const { openStart, closeEnd } = data;
|
||||||
|
|
||||||
|
const attributes = getAttributes(data);
|
||||||
|
const presetName = getAttribute(data, 'rocket-image');
|
||||||
|
const src = getAttribute(data, 'src');
|
||||||
|
const title = getAttribute(data, 'title');
|
||||||
|
const alt = getAttribute(data, 'alt');
|
||||||
|
if (presetName) {
|
||||||
|
images.push({
|
||||||
|
presetName,
|
||||||
|
attributes,
|
||||||
|
src,
|
||||||
|
title,
|
||||||
|
alt,
|
||||||
|
openStart,
|
||||||
|
closeEnd,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
parser.write(Buffer.from(html, 'utf8'));
|
||||||
|
parser.end();
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSrcsetAttribute(imageFormat) {
|
||||||
|
return `srcset="${imageFormat.map(entry => entry.srcset).join(', ')}"`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function responsiveImages(images, { inputPath, outputDir, imagePresets = {} }) {
|
||||||
|
for (let i = 0; i < images.length; i += 1) {
|
||||||
|
const { alt, filePath, title, src, presetName, attributes } = images[i];
|
||||||
|
|
||||||
|
if (alt === undefined) {
|
||||||
|
throw new Error(`Missing \`alt\` on responsive image from: ${src} in ${inputPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const presetSettings = imagePresets[presetName];
|
||||||
|
if (!presetSettings) {
|
||||||
|
throw new Error(`Could not find imagePresets: { ${presetName}: {} }`);
|
||||||
|
}
|
||||||
|
const sizes = presetSettings.sizes || '100vw';
|
||||||
|
|
||||||
|
const metadata = await EleventyImage(filePath, {
|
||||||
|
outputDir: path.join(outputDir, 'images'),
|
||||||
|
urlPath: '/images/',
|
||||||
|
...presetSettings,
|
||||||
|
});
|
||||||
|
const lowsrc = metadata.jpeg[0];
|
||||||
|
|
||||||
|
let pictureStartWithSources = '';
|
||||||
|
let srcsetAttribute = '';
|
||||||
|
let sizesAttribute = '';
|
||||||
|
let pictureEnd = '';
|
||||||
|
|
||||||
|
if (Object.keys(metadata).length > 1) {
|
||||||
|
const sources = Object.values(metadata)
|
||||||
|
.map(imageFormat => {
|
||||||
|
return `<source type="${imageFormat[0].sourceType}" ${getSrcsetAttribute(
|
||||||
|
imageFormat,
|
||||||
|
)} sizes="${sizes}">`;
|
||||||
|
})
|
||||||
|
.join('\n');
|
||||||
|
pictureStartWithSources = `<picture>\n${sources}`;
|
||||||
|
pictureEnd = '</picture>';
|
||||||
|
} else {
|
||||||
|
srcsetAttribute = getSrcsetAttribute(Object.values(metadata)[0]);
|
||||||
|
sizesAttribute = `sizes="${sizes}"`;
|
||||||
|
}
|
||||||
|
const attributesString = attributes
|
||||||
|
.filter(attribute => !['src', 'title'].includes(attribute.name))
|
||||||
|
.map(attribute => `${attribute.name}="${attribute.value}"`)
|
||||||
|
.join(' ');
|
||||||
|
|
||||||
|
const figureStart = title ? '<figure>' : '';
|
||||||
|
const figureEndWithCaption = title ? `<figcaption>${title}</figcaption>\n</figure>` : '';
|
||||||
|
|
||||||
|
images[i].newHtml = `
|
||||||
|
${figureStart}
|
||||||
|
${pictureStartWithSources}
|
||||||
|
<img
|
||||||
|
${attributesString}
|
||||||
|
src="${lowsrc.url}"
|
||||||
|
${srcsetAttribute}
|
||||||
|
${sizesAttribute}
|
||||||
|
width="${lowsrc.width}"
|
||||||
|
height="${lowsrc.height}"
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
${pictureEnd}
|
||||||
|
${figureEndWithCaption}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateHtml(html, changes) {
|
||||||
|
let newHtml = html;
|
||||||
|
for (const change of changes) {
|
||||||
|
newHtml = replaceBetween({
|
||||||
|
html: newHtml,
|
||||||
|
start: change.openStart,
|
||||||
|
end: change.closeEnd,
|
||||||
|
insert: change.newHtml,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return newHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveFilePath(images, { inputPath }) {
|
||||||
|
for (let i = 0; i < images.length; i += 1) {
|
||||||
|
images[i].filePath = path.join(path.dirname(inputPath), images[i].src);
|
||||||
|
}
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
let isSetup = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} html
|
||||||
|
*/
|
||||||
|
async function insertResponsiveImages(html) {
|
||||||
|
const config = getComputedConfig();
|
||||||
|
|
||||||
|
if (!isSetup) {
|
||||||
|
await parser.prepareWasm(saxWasmBuffer);
|
||||||
|
isSetup = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
inputPath: this.inputPath,
|
||||||
|
outputDir: this.outputDir,
|
||||||
|
imagePresets: config.imagePresets,
|
||||||
|
};
|
||||||
|
|
||||||
|
let images = getImages(html);
|
||||||
|
images = resolveFilePath(images, options);
|
||||||
|
images = await responsiveImages(images, options);
|
||||||
|
const newHtml = updateHtml(html, images);
|
||||||
|
|
||||||
|
return newHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
insertResponsiveImages,
|
||||||
|
};
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const slash = require('slash');
|
||||||
const { readdirSync } = require('fs');
|
const { readdirSync } = require('fs');
|
||||||
|
|
||||||
function getDirectories(source) {
|
function getDirectories(source) {
|
||||||
@@ -23,7 +24,7 @@ const rocketCollections = {
|
|||||||
let docs = [
|
let docs = [
|
||||||
...collection.getFilteredByGlob(`${_inputDirCwdRelative}/${section}/**/*.md`),
|
...collection.getFilteredByGlob(`${_inputDirCwdRelative}/${section}/**/*.md`),
|
||||||
];
|
];
|
||||||
docs = docs.filter(page => page.inputPath !== `./${indexSection}`);
|
docs = docs.filter(page => page.inputPath !== `./${slash(indexSection)}`);
|
||||||
|
|
||||||
return docs;
|
return docs;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { processLocalReferences } = require('./processLocalReferences.cjs');
|
const { processLocalReferences } = require('./processLocalReferences.cjs');
|
||||||
|
const { insertResponsiveImages } = require('./insertResponsiveImages.cjs');
|
||||||
|
|
||||||
function inlineFilePath(filePath) {
|
function inlineFilePath(filePath) {
|
||||||
let data = fs.readFileSync(filePath, function (err, contents) {
|
let data = fs.readFileSync(filePath, function (err, contents) {
|
||||||
@@ -24,6 +25,7 @@ const rocketFilters = {
|
|||||||
|
|
||||||
eleventyConfig.addFilter('inlineFilePath', inlineFilePath);
|
eleventyConfig.addFilter('inlineFilePath', inlineFilePath);
|
||||||
|
|
||||||
|
eleventyConfig.addTransform('insertResponsiveImages', insertResponsiveImages);
|
||||||
eleventyConfig.addTransform('processLocalReferences', processLocalReferences);
|
eleventyConfig.addTransform('processLocalReferences', processLocalReferences);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,15 +40,29 @@ export async function normalizeConfig(inConfig) {
|
|||||||
inputDir: 'docs',
|
inputDir: 'docs',
|
||||||
outputDir: '_site',
|
outputDir: '_site',
|
||||||
outputDevDir: '_site-dev',
|
outputDevDir: '_site-dev',
|
||||||
|
serviceWorkerName: 'service-worker.js',
|
||||||
build: {},
|
build: {},
|
||||||
devServer: {},
|
devServer: {},
|
||||||
|
|
||||||
...inConfig,
|
...inConfig,
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
widths: [600, 900, 1640],
|
||||||
|
formats: ['avif', 'jpeg'],
|
||||||
|
sizes: '100vw',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (inConfig && inConfig.devServer) {
|
if (inConfig && inConfig.devServer) {
|
||||||
config.devServer = { ...config.devServer, ...inConfig.devServer };
|
config.devServer = { ...config.devServer, ...inConfig.devServer };
|
||||||
}
|
}
|
||||||
|
if (inConfig.imagePresets && inConfig.imagePresets.responsive) {
|
||||||
|
config.imagePresets.responsive = {
|
||||||
|
...config.imagePresets.responsive,
|
||||||
|
...inConfig.imagePresets.responsive,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let userConfigFile;
|
let userConfigFile;
|
||||||
let __configDir = process.cwd();
|
let __configDir = process.cwd();
|
||||||
@@ -72,7 +86,14 @@ export async function normalizeConfig(inConfig) {
|
|||||||
...config.devServer,
|
...config.devServer,
|
||||||
...fileConfig.devServer,
|
...fileConfig.devServer,
|
||||||
},
|
},
|
||||||
|
imagePresets: config.imagePresets,
|
||||||
};
|
};
|
||||||
|
if (fileConfig.imagePresets && fileConfig.imagePresets.responsive) {
|
||||||
|
config.imagePresets.responsive = {
|
||||||
|
...config.imagePresets.responsive,
|
||||||
|
...fileConfig.imagePresets.responsive,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Could not read rocket config file', error);
|
console.error('Could not read rocket config file', error);
|
||||||
@@ -87,6 +108,10 @@ export async function normalizeConfig(inConfig) {
|
|||||||
for (const preset of config.presets) {
|
for (const preset of config.presets) {
|
||||||
config._presetPathes.push(preset.path);
|
config._presetPathes.push(preset.path);
|
||||||
|
|
||||||
|
if (preset.adjustImagePresets) {
|
||||||
|
config.imagePresets = preset.adjustImagePresets(config.imagePresets);
|
||||||
|
}
|
||||||
|
|
||||||
if (preset.setupUnifiedPlugins) {
|
if (preset.setupUnifiedPlugins) {
|
||||||
config.setupUnifiedPlugins = [...config.setupUnifiedPlugins, ...preset.setupUnifiedPlugins];
|
config.setupUnifiedPlugins = [...config.setupUnifiedPlugins, ...preset.setupUnifiedPlugins];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,16 @@ const { getComputedConfig } = require('../public/computedConfig.cjs');
|
|||||||
const rocketFilters = require('../eleventy-plugins/rocketFilters.cjs');
|
const rocketFilters = require('../eleventy-plugins/rocketFilters.cjs');
|
||||||
const rocketCopy = require('../eleventy-plugins/rocketCopy.cjs');
|
const rocketCopy = require('../eleventy-plugins/rocketCopy.cjs');
|
||||||
const rocketCollections = require('../eleventy-plugins/rocketCollections.cjs');
|
const rocketCollections = require('../eleventy-plugins/rocketCollections.cjs');
|
||||||
|
const { adjustPluginOptions } = require('plugins-manager');
|
||||||
|
const image = require('./mdjsImageHandler.cjs');
|
||||||
|
|
||||||
|
const defaultSetupUnifiedPlugins = [
|
||||||
|
adjustPluginOptions('remark2rehype', {
|
||||||
|
handlers: {
|
||||||
|
image,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
module.exports = function (eleventyConfig) {
|
module.exports = function (eleventyConfig) {
|
||||||
const config = getComputedConfig();
|
const config = getComputedConfig();
|
||||||
@@ -28,7 +38,9 @@ module.exports = function (eleventyConfig) {
|
|||||||
{
|
{
|
||||||
name: 'eleventy-plugin-mdjs-unified',
|
name: 'eleventy-plugin-mdjs-unified',
|
||||||
plugin: eleventyPluginMdjsUnified,
|
plugin: eleventyPluginMdjsUnified,
|
||||||
options: { setupUnifiedPlugins: config.setupUnifiedPlugins },
|
options: {
|
||||||
|
setupUnifiedPlugins: [...defaultSetupUnifiedPlugins, ...config.setupUnifiedPlugins],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'eleventy-rocket-nav',
|
name: 'eleventy-rocket-nav',
|
||||||
|
|||||||
17
packages/cli/src/shared/mdjsImageHandler.cjs
Normal file
17
packages/cli/src/shared/mdjsImageHandler.cjs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
const normalize = require('mdurl/encode');
|
||||||
|
|
||||||
|
function image(h, node) {
|
||||||
|
const props = {
|
||||||
|
src: normalize(node.url),
|
||||||
|
alt: node.alt,
|
||||||
|
'rocket-image': 'responsive',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (node.title !== null && node.title !== undefined) {
|
||||||
|
props.title = node.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h(node, 'img', props);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = image;
|
||||||
@@ -15,7 +15,6 @@ export function setFixtureDir(importMetaUrl) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {object} readOutputOptions
|
* @typedef {object} readOutputOptions
|
||||||
* @property {boolean} stripServiceWorker
|
|
||||||
* @property {boolean} stripToBody
|
* @property {boolean} stripToBody
|
||||||
* @property {boolean} stripStartEndWhitespace
|
* @property {boolean} stripStartEndWhitespace
|
||||||
* @property {boolean} stripScripts
|
* @property {boolean} stripScripts
|
||||||
@@ -47,7 +46,6 @@ export async function readOutput(
|
|||||||
cli,
|
cli,
|
||||||
fileName,
|
fileName,
|
||||||
{
|
{
|
||||||
stripServiceWorker = false,
|
|
||||||
stripToBody = false,
|
stripToBody = false,
|
||||||
stripStartEndWhitespace = true,
|
stripStartEndWhitespace = true,
|
||||||
stripScripts = false,
|
stripScripts = false,
|
||||||
@@ -67,11 +65,6 @@ export async function readOutput(
|
|||||||
const bodyCloseTagStart = text.indexOf('</body>');
|
const bodyCloseTagStart = text.indexOf('</body>');
|
||||||
text = text.substring(bodyOpenTagEnd, bodyCloseTagStart);
|
text = text.substring(bodyOpenTagEnd, bodyCloseTagStart);
|
||||||
}
|
}
|
||||||
if (stripServiceWorker) {
|
|
||||||
const scriptOpenTagEnd = text.indexOf('<script inject-service-worker');
|
|
||||||
const scriptCloseTagStart = text.indexOf('</script>', scriptOpenTagEnd) + 9;
|
|
||||||
text = text.substring(0, scriptOpenTagEnd) + text.substring(scriptCloseTagStart);
|
|
||||||
}
|
|
||||||
if (stripScripts) {
|
if (stripScripts) {
|
||||||
const scriptOpenTagEnd = text.indexOf('<script>');
|
const scriptOpenTagEnd = text.indexOf('<script>');
|
||||||
const scriptCloseTagStart = text.indexOf('</script>', scriptOpenTagEnd) + 9;
|
const scriptCloseTagStart = text.indexOf('</script>', scriptOpenTagEnd) + 9;
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ describe('RocketCli computedConfig', () => {
|
|||||||
|
|
||||||
const indexHtml = await readBuildOutput(cli, 'index.html', {
|
const indexHtml = await readBuildOutput(cli, 'index.html', {
|
||||||
stripToBody: true,
|
stripToBody: true,
|
||||||
stripServiceWorker: true,
|
|
||||||
});
|
});
|
||||||
expect(indexHtml).to.equal('/_merged_assets/11ty-img/5893749-1200.png');
|
expect(indexHtml).to.equal('/_merged_assets/11ty-img/5893749-1200.png');
|
||||||
});
|
});
|
||||||
@@ -107,31 +106,33 @@ describe('RocketCli computedConfig', () => {
|
|||||||
cli = await executeStart('computed-config-fixtures/image-link/rocket.config.js');
|
cli = await executeStart('computed-config-fixtures/image-link/rocket.config.js');
|
||||||
|
|
||||||
const namedMdContent = [
|
const namedMdContent = [
|
||||||
'<p><a href="../">Root</a>',
|
'<p>',
|
||||||
'<a href="../one-level/raw/">Raw</a>',
|
' <a href="../">Root</a>',
|
||||||
'<img src="../images/my-img.svg" alt="my-img">',
|
' <a href="../one-level/raw/">Raw</a>',
|
||||||
'<img src="/images/my-img.svg" alt="absolute-img"></p>',
|
' <img src="../images/my-img.svg" alt="my-img" />',
|
||||||
|
' <img src="/images/my-img.svg" alt="absolute-img" />',
|
||||||
|
'</p>',
|
||||||
];
|
];
|
||||||
|
|
||||||
const namedHtmlContent = [
|
const namedHtmlContent = [
|
||||||
'<div id="with-anchor">',
|
'<div id="with-anchor">',
|
||||||
' <a href="../">Root</a>',
|
' <a href="../">Root</a>',
|
||||||
' <a href="../one-level/raw/">Raw</a>',
|
' <a href="../one-level/raw/">Raw</a>',
|
||||||
' <img src="../images/my-img.svg" alt="my-img">',
|
' <img src="../images/my-img.svg" alt="my-img" />',
|
||||||
' <img src="/images/my-img.svg" alt="absolute-img">',
|
' <img src="/images/my-img.svg" alt="absolute-img" />',
|
||||||
' <picture>',
|
' <picture>',
|
||||||
' <source media="(min-width:465px)" srcset="../images/picture-min-465.jpg">',
|
' <source media="(min-width:465px)" srcset="../images/picture-min-465.jpg" />',
|
||||||
' <img src="../images/picture-fallback.jpg" alt="Fallback" style="width:auto;">',
|
' <img src="../images/picture-fallback.jpg" alt="Fallback" style="width: auto" />',
|
||||||
' </picture>',
|
' </picture>',
|
||||||
'</div>',
|
'</div>',
|
||||||
];
|
];
|
||||||
|
|
||||||
const templateHtml = await readStartOutput(cli, 'template/index.html');
|
const templateHtml = await readStartOutput(cli, 'template/index.html', { formatHtml: true });
|
||||||
expect(templateHtml, 'template/index.html does not match').to.equal(
|
expect(templateHtml, 'template/index.html does not match').to.equal(
|
||||||
namedHtmlContent.join('\n'),
|
namedHtmlContent.join('\n'),
|
||||||
);
|
);
|
||||||
|
|
||||||
const guidesHtml = await readStartOutput(cli, 'guides/index.html');
|
const guidesHtml = await readStartOutput(cli, 'guides/index.html', { formatHtml: true });
|
||||||
expect(guidesHtml, 'guides/index.html does not match').to.equal(
|
expect(guidesHtml, 'guides/index.html does not match').to.equal(
|
||||||
[...namedMdContent, ...namedHtmlContent].join('\n'),
|
[...namedMdContent, ...namedHtmlContent].join('\n'),
|
||||||
);
|
);
|
||||||
@@ -158,27 +159,28 @@ describe('RocketCli computedConfig', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// for index files no '../' will be added
|
// for index files no '../' will be added
|
||||||
const indexHtml = await readStartOutput(cli, 'index.html');
|
const indexHtml = await readStartOutput(cli, 'index.html', { formatHtml: true });
|
||||||
expect(indexHtml, 'index.html does not match').to.equal(
|
expect(indexHtml, 'index.html does not match').to.equal(
|
||||||
[
|
[
|
||||||
'<p><a href="./">Root</a>',
|
'<p>',
|
||||||
'<a href="guides/#with-anchor">Guides</a>',
|
|
||||||
'<a href="./one-level/raw/">Raw</a>',
|
|
||||||
'<a href="template/">Template</a>',
|
|
||||||
'<a href="./rules/tabindex/">EndingIndex</a>',
|
|
||||||
'<img src="./images/my-img.svg" alt="my-img">',
|
|
||||||
'<img src="/images/my-img.svg" alt="absolute-img"></p>',
|
|
||||||
'<div>',
|
|
||||||
' <a href="./">Root</a>',
|
' <a href="./">Root</a>',
|
||||||
' 👇<a href="guides/#with-anchor">Guides</a>',
|
' <a href="guides/#with-anchor">Guides</a>',
|
||||||
' 👉 <a href="./one-level/raw/">Raw</a>',
|
' <a href="./one-level/raw/">Raw</a>',
|
||||||
' <a href="template/">Template</a>',
|
' <a href="template/">Template</a>',
|
||||||
' <a href="./rules/tabindex/">EndingIndex</a>',
|
' <a href="./rules/tabindex/">EndingIndex</a>',
|
||||||
' <img src="./images/my-img.svg" alt="my-img">',
|
' <img src="./images/my-img.svg" alt="my-img" />',
|
||||||
' <img src="/images/my-img.svg" alt="absolute-img">',
|
' <img src="/images/my-img.svg" alt="absolute-img" />',
|
||||||
|
'</p>',
|
||||||
|
'<div>',
|
||||||
|
' <a href="./">Root</a>',
|
||||||
|
' 👇<a href="guides/#with-anchor">Guides</a> 👉 <a href="./one-level/raw/">Raw</a>',
|
||||||
|
' <a href="template/">Template</a>',
|
||||||
|
' <a href="./rules/tabindex/">EndingIndex</a>',
|
||||||
|
' <img src="./images/my-img.svg" alt="my-img" />',
|
||||||
|
' <img src="/images/my-img.svg" alt="absolute-img" />',
|
||||||
' <picture>',
|
' <picture>',
|
||||||
' <source media="(min-width:465px)" srcset="./images/picture-min-465.jpg">',
|
' <source media="(min-width:465px)" srcset="./images/picture-min-465.jpg" />',
|
||||||
' <img src="./images/picture-fallback.jpg" alt="Fallback" style="width:auto;">',
|
' <img src="./images/picture-fallback.jpg" alt="Fallback" style="width: auto" />',
|
||||||
' </picture>',
|
' </picture>',
|
||||||
'</div>',
|
'</div>',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
|
|||||||
@@ -75,9 +75,6 @@ describe('RocketCli e2e', () => {
|
|||||||
cli = await executeBuild('e2e-fixtures/rollup-plugin/devbuild-build.rocket.config.js');
|
cli = await executeBuild('e2e-fixtures/rollup-plugin/devbuild-build.rocket.config.js');
|
||||||
const inlineModule = await readBuildOutput(cli, 'e97af63d.js');
|
const inlineModule = await readBuildOutput(cli, 'e97af63d.js');
|
||||||
expect(inlineModule).to.equal('var a={test:"data"};console.log(a);');
|
expect(inlineModule).to.equal('var a={test:"data"};console.log(a);');
|
||||||
|
|
||||||
const swCode = await readBuildOutput(cli, 'my-service-worker.js');
|
|
||||||
expect(swCode).to.not.be.undefined;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can adjust the inputDir', async () => {
|
it('can adjust the inputDir', async () => {
|
||||||
@@ -111,7 +108,6 @@ describe('RocketCli e2e', () => {
|
|||||||
cli = await executeBuild('e2e-fixtures/content/pathPrefix.rocket.config.js');
|
cli = await executeBuild('e2e-fixtures/content/pathPrefix.rocket.config.js');
|
||||||
|
|
||||||
const linkHtml = await readBuildOutput(cli, 'link/index.html', {
|
const linkHtml = await readBuildOutput(cli, 'link/index.html', {
|
||||||
stripServiceWorker: true,
|
|
||||||
stripToBody: true,
|
stripToBody: true,
|
||||||
});
|
});
|
||||||
expect(linkHtml).to.equal(
|
expect(linkHtml).to.equal(
|
||||||
@@ -119,9 +115,7 @@ describe('RocketCli e2e', () => {
|
|||||||
'\n',
|
'\n',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const assetHtml = await readBuildOutput(cli, 'use-assets/index.html', {
|
const assetHtml = await readBuildOutput(cli, 'use-assets/index.html');
|
||||||
stripServiceWorker: true,
|
|
||||||
});
|
|
||||||
expect(assetHtml).to.equal(
|
expect(assetHtml).to.equal(
|
||||||
'<html><head><link rel="stylesheet" href="../41297ffa.css">\n\n</head><body>\n\n</body></html>',
|
'<html><head><link rel="stylesheet" href="../41297ffa.css">\n\n</head><body>\n\n</body></html>',
|
||||||
);
|
);
|
||||||
|
|||||||
201
packages/cli/test-node/RocketCli.images.test.js
Normal file
201
packages/cli/test-node/RocketCli.images.test.js
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
import chai from 'chai';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import { executeStart, readStartOutput, setFixtureDir } from '@rocket/cli/test-helpers';
|
||||||
|
|
||||||
|
const { expect } = chai;
|
||||||
|
|
||||||
|
describe('RocketCli images', () => {
|
||||||
|
let cli;
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
// ignore colors in tests as most CIs won't support it
|
||||||
|
chalk.level = 0;
|
||||||
|
setFixtureDir(import.meta.url);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
if (cli?.cleanup) {
|
||||||
|
await cli.cleanup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Images', () => {
|
||||||
|
it('does render content images responsive', async () => {
|
||||||
|
cli = await executeStart('e2e-fixtures/images/rocket.config.js');
|
||||||
|
const indexHtml = await readStartOutput(cli, 'index.html', { formatHtml: true });
|
||||||
|
expect(indexHtml).to.equal(
|
||||||
|
[
|
||||||
|
'<p>',
|
||||||
|
' <figure>',
|
||||||
|
' <picture>',
|
||||||
|
' <source',
|
||||||
|
' type="image/avif"',
|
||||||
|
' srcset="/images/d67643ad-600.avif 600w, /images/d67643ad-900.avif 900w"',
|
||||||
|
' sizes="100vw"',
|
||||||
|
' />',
|
||||||
|
' <source',
|
||||||
|
' type="image/jpeg"',
|
||||||
|
' srcset="/images/d67643ad-600.jpeg 600w, /images/d67643ad-900.jpeg 900w"',
|
||||||
|
' sizes="100vw"',
|
||||||
|
' />',
|
||||||
|
' <img',
|
||||||
|
' alt="My Image Alternative Text"',
|
||||||
|
' rocket-image="responsive"',
|
||||||
|
' src="/images/d67643ad-600.jpeg"',
|
||||||
|
' width="600"',
|
||||||
|
' height="316"',
|
||||||
|
' loading="lazy"',
|
||||||
|
' decoding="async"',
|
||||||
|
' />',
|
||||||
|
' </picture>',
|
||||||
|
' <figcaption>My Image Description</figcaption>',
|
||||||
|
' </figure>',
|
||||||
|
'</p>',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders multiple images in the correct order', async () => {
|
||||||
|
cli = await executeStart('e2e-fixtures/images/rocket.config.js');
|
||||||
|
const indexHtml = await readStartOutput(cli, 'two-images/index.html', { formatHtml: true });
|
||||||
|
expect(indexHtml).to.equal(
|
||||||
|
[
|
||||||
|
'<p>',
|
||||||
|
' <picture>',
|
||||||
|
' <source',
|
||||||
|
' type="image/avif"',
|
||||||
|
' srcset="/images/d67643ad-600.avif 600w, /images/d67643ad-900.avif 900w"',
|
||||||
|
' sizes="100vw"',
|
||||||
|
' />',
|
||||||
|
' <source',
|
||||||
|
' type="image/jpeg"',
|
||||||
|
' srcset="/images/d67643ad-600.jpeg 600w, /images/d67643ad-900.jpeg 900w"',
|
||||||
|
' sizes="100vw"',
|
||||||
|
' />',
|
||||||
|
' <img',
|
||||||
|
' alt="one"',
|
||||||
|
' rocket-image="responsive"',
|
||||||
|
' src="/images/d67643ad-600.jpeg"',
|
||||||
|
' width="600"',
|
||||||
|
' height="316"',
|
||||||
|
' loading="lazy"',
|
||||||
|
' decoding="async"',
|
||||||
|
' />',
|
||||||
|
' </picture>',
|
||||||
|
'',
|
||||||
|
' <picture>',
|
||||||
|
' <source',
|
||||||
|
' type="image/avif"',
|
||||||
|
' srcset="/images/d67643ad-600.avif 600w, /images/d67643ad-900.avif 900w"',
|
||||||
|
' sizes="100vw"',
|
||||||
|
' />',
|
||||||
|
' <source',
|
||||||
|
' type="image/jpeg"',
|
||||||
|
' srcset="/images/d67643ad-600.jpeg 600w, /images/d67643ad-900.jpeg 900w"',
|
||||||
|
' sizes="100vw"',
|
||||||
|
' />',
|
||||||
|
' <img',
|
||||||
|
' alt="two"',
|
||||||
|
' rocket-image="responsive"',
|
||||||
|
' src="/images/d67643ad-600.jpeg"',
|
||||||
|
' width="600"',
|
||||||
|
' height="316"',
|
||||||
|
' loading="lazy"',
|
||||||
|
' decoding="async"',
|
||||||
|
' />',
|
||||||
|
' </picture>',
|
||||||
|
'</p>',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can configure those responsive images', async () => {
|
||||||
|
cli = await executeStart('e2e-fixtures/images/small.rocket.config.js');
|
||||||
|
const indexHtml = await readStartOutput(cli, 'index.html', { formatHtml: true });
|
||||||
|
expect(indexHtml).to.equal(
|
||||||
|
[
|
||||||
|
'<p>',
|
||||||
|
' <figure>',
|
||||||
|
' <picture>',
|
||||||
|
' <source',
|
||||||
|
' type="image/avif"',
|
||||||
|
' srcset="/images/d67643ad-30.avif 30w, /images/d67643ad-60.avif 60w"',
|
||||||
|
' sizes="(min-width: 1024px) 30px, 60px"',
|
||||||
|
' />',
|
||||||
|
' <source',
|
||||||
|
' type="image/jpeg"',
|
||||||
|
' srcset="/images/d67643ad-30.jpeg 30w, /images/d67643ad-60.jpeg 60w"',
|
||||||
|
' sizes="(min-width: 1024px) 30px, 60px"',
|
||||||
|
' />',
|
||||||
|
' <img',
|
||||||
|
' alt="My Image Alternative Text"',
|
||||||
|
' rocket-image="responsive"',
|
||||||
|
' src="/images/d67643ad-30.jpeg"',
|
||||||
|
' width="30"',
|
||||||
|
' height="15"',
|
||||||
|
' loading="lazy"',
|
||||||
|
' decoding="async"',
|
||||||
|
' />',
|
||||||
|
' </picture>',
|
||||||
|
' <figcaption>My Image Description</figcaption>',
|
||||||
|
' </figure>',
|
||||||
|
'</p>',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will only render a figure & figcaption if there is a caption/title', async () => {
|
||||||
|
cli = await executeStart('e2e-fixtures/images/small.rocket.config.js');
|
||||||
|
const indexHtml = await readStartOutput(cli, 'no-title/index.html', { formatHtml: true });
|
||||||
|
expect(indexHtml).to.equal(
|
||||||
|
[
|
||||||
|
'<p>',
|
||||||
|
' <picture>',
|
||||||
|
' <source',
|
||||||
|
' type="image/avif"',
|
||||||
|
' srcset="/images/d67643ad-30.avif 30w, /images/d67643ad-60.avif 60w"',
|
||||||
|
' sizes="(min-width: 1024px) 30px, 60px"',
|
||||||
|
' />',
|
||||||
|
' <source',
|
||||||
|
' type="image/jpeg"',
|
||||||
|
' srcset="/images/d67643ad-30.jpeg 30w, /images/d67643ad-60.jpeg 60w"',
|
||||||
|
' sizes="(min-width: 1024px) 30px, 60px"',
|
||||||
|
' />',
|
||||||
|
' <img',
|
||||||
|
' alt="My Image Alternative Text"',
|
||||||
|
' rocket-image="responsive"',
|
||||||
|
' src="/images/d67643ad-30.jpeg"',
|
||||||
|
' width="30"',
|
||||||
|
' height="15"',
|
||||||
|
' loading="lazy"',
|
||||||
|
' decoding="async"',
|
||||||
|
' />',
|
||||||
|
' </picture>',
|
||||||
|
'</p>',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will render an img with srcset and sizes if there is only one image format', async () => {
|
||||||
|
cli = await executeStart('e2e-fixtures/images/single-format.rocket.config.js');
|
||||||
|
const indexHtml = await readStartOutput(cli, 'no-title/index.html', { formatHtml: true });
|
||||||
|
expect(indexHtml).to.equal(
|
||||||
|
[
|
||||||
|
'<p>',
|
||||||
|
' <img',
|
||||||
|
' alt="My Image Alternative Text"',
|
||||||
|
' rocket-image="responsive"',
|
||||||
|
' src="/images/d67643ad-30.jpeg"',
|
||||||
|
' srcset="/images/d67643ad-30.jpeg 30w, /images/d67643ad-60.jpeg 60w"',
|
||||||
|
' sizes="(min-width: 1024px) 30px, 60px"',
|
||||||
|
' width="30"',
|
||||||
|
' height="15"',
|
||||||
|
' loading="lazy"',
|
||||||
|
' decoding="async"',
|
||||||
|
' />',
|
||||||
|
'</p>',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -86,6 +86,12 @@ describe('RocketCli preset', () => {
|
|||||||
' </div>',
|
' </div>',
|
||||||
'',
|
'',
|
||||||
' <footer id="main-footer"></footer>',
|
' <footer id="main-footer"></footer>',
|
||||||
|
'',
|
||||||
|
' <script',
|
||||||
|
' type="module"',
|
||||||
|
' inject-service-worker=""',
|
||||||
|
' src="/_merged_assets/scripts/registerServiceWorker.js"',
|
||||||
|
' ></script>',
|
||||||
' </body>',
|
' </body>',
|
||||||
'</html>',
|
'</html>',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
@@ -98,4 +104,27 @@ describe('RocketCli preset', () => {
|
|||||||
const indexHtml = await readStartOutput(cli, 'index.html');
|
const indexHtml = await readStartOutput(cli, 'index.html');
|
||||||
expect(indexHtml).to.include('<meta name="added" content="at the top" />');
|
expect(indexHtml).to.include('<meta name="added" content="at the top" />');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('a preset can provide an adjustImagePresets() function', async () => {
|
||||||
|
cli = await executeStart('preset-fixtures/use-preset/rocket.config.js');
|
||||||
|
|
||||||
|
const indexHtml = await readStartOutput(cli, 'index.html', { formatHtml: true });
|
||||||
|
expect(indexHtml).to.equal(
|
||||||
|
[
|
||||||
|
'<p>',
|
||||||
|
' <img',
|
||||||
|
' alt="My Image Alternative Text"',
|
||||||
|
' rocket-image="responsive"',
|
||||||
|
' src="/images/1f847765-30.jpeg"',
|
||||||
|
' srcset="/images/1f847765-30.jpeg 30w, /images/1f847765-60.jpeg 60w"',
|
||||||
|
' sizes="30px"',
|
||||||
|
' width="30"',
|
||||||
|
' height="15"',
|
||||||
|
' loading="lazy"',
|
||||||
|
' decoding="async"',
|
||||||
|
' />',
|
||||||
|
'</p>',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -34,12 +34,7 @@ describe('RocketCli use cases', () => {
|
|||||||
expect(aboutHtml).to.equal(
|
expect(aboutHtml).to.equal(
|
||||||
[
|
[
|
||||||
'<p><code>about.md</code></p>',
|
'<p><code>about.md</code></p>',
|
||||||
'<script type="module">',
|
'<script type="module" src="/about/__mdjs-stories.js" mdjs-setup></script>',
|
||||||
' import { myData } from "../sub/assets/myData.js";',
|
|
||||||
' import("../sub/assets/myData.js");',
|
|
||||||
' const name = "myData";',
|
|
||||||
' import(`../sub/assets/${name}.js`);',
|
|
||||||
'</script>',
|
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -47,12 +42,7 @@ describe('RocketCli use cases', () => {
|
|||||||
expect(subHtml).to.equal(
|
expect(subHtml).to.equal(
|
||||||
[
|
[
|
||||||
'<p><code>sub/index.md</code></p>',
|
'<p><code>sub/index.md</code></p>',
|
||||||
'<script type="module">',
|
'<script type="module" src="/sub/__mdjs-stories.js" mdjs-setup></script>',
|
||||||
' import { myData } from "./assets/myData.js";',
|
|
||||||
' import("./assets/myData.js");',
|
|
||||||
' const name = "myData";',
|
|
||||||
' import(`./assets/${name}.js`);',
|
|
||||||
'</script>',
|
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -62,12 +52,7 @@ describe('RocketCli use cases', () => {
|
|||||||
expect(subDetailsHtml).to.equal(
|
expect(subDetailsHtml).to.equal(
|
||||||
[
|
[
|
||||||
'<p><code>sub/details.md</code></p>',
|
'<p><code>sub/details.md</code></p>',
|
||||||
'<script type="module">',
|
'<script type="module" src="/sub/details/__mdjs-stories.js" mdjs-setup></script>',
|
||||||
' import { myData } from "../assets/myData.js";',
|
|
||||||
' import("../assets/myData.js");',
|
|
||||||
' const name = "myData";',
|
|
||||||
' import(`../assets/${name}.js`);',
|
|
||||||
'</script>',
|
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -75,12 +60,7 @@ describe('RocketCli use cases', () => {
|
|||||||
expect(indexHtml).to.equal(
|
expect(indexHtml).to.equal(
|
||||||
[
|
[
|
||||||
'<p><code>index.md</code></p>',
|
'<p><code>index.md</code></p>',
|
||||||
'<script type="module">',
|
'<script type="module" src="/__mdjs-stories.js" mdjs-setup></script>',
|
||||||
' import { myData } from "./sub/assets/myData.js";',
|
|
||||||
' import("./sub/assets/myData.js");',
|
|
||||||
' const name = "myData";',
|
|
||||||
' import(`./sub/assets/${name}.js`);',
|
|
||||||
'</script>',
|
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,20 @@
|
|||||||
|
import { adjustPluginOptions } from 'plugins-manager';
|
||||||
|
|
||||||
|
function image(h, node) {
|
||||||
|
return h(node, 'img', {
|
||||||
|
src: node.url,
|
||||||
|
alt: node.alt,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
|
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
|
||||||
const config = {};
|
const config = {
|
||||||
|
setupUnifiedPlugins: [
|
||||||
|
adjustPluginOptions('remark2rehype', {
|
||||||
|
handlers: {
|
||||||
|
image,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
export default config;
|
export default config;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
**/*.njk
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
5
packages/cli/test-node/e2e-fixtures/images/docs/index.md
Normal file
5
packages/cli/test-node/e2e-fixtures/images/docs/index.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
layout: layout-raw
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
layout: layout-raw
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
layout: layout-raw
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
|
||||||
|
const config = {};
|
||||||
|
export default config;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
|
||||||
|
const config = {
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
widths: [30, 60],
|
||||||
|
formats: ['jpeg'],
|
||||||
|
sizes: '(min-width: 1024px) 30px, 60px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export default config;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
|
||||||
|
const config = {
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
widths: [30, 60],
|
||||||
|
formats: ['avif', 'jpeg'],
|
||||||
|
sizes: '(min-width: 1024px) 30px, 60px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export default config;
|
||||||
@@ -1,19 +1,11 @@
|
|||||||
// @ts-no-check
|
// @ts-no-check
|
||||||
import path from 'path';
|
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
|
|
||||||
import json from '@rollup/plugin-json';
|
import json from '@rollup/plugin-json';
|
||||||
import { addPlugin, adjustPluginOptions } from 'plugins-manager';
|
import { addPlugin, adjustPluginOptions } from 'plugins-manager';
|
||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
||||||
const outputDir = path.join(__dirname, '__output');
|
|
||||||
|
|
||||||
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
|
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
|
||||||
const config = {
|
const config = {
|
||||||
setupDevAndBuildPlugins: [addPlugin({ name: 'json', plugin: json, location: 'top' })],
|
setupDevAndBuildPlugins: [addPlugin({ name: 'json', plugin: json, location: 'top' })],
|
||||||
setupBuildPlugins: [
|
setupBuildPlugins: [adjustPluginOptions('html', { absoluteBaseUrl: 'https://test-me.com' })],
|
||||||
adjustPluginOptions('workbox', { swDest: path.join(outputDir, 'my-service-worker.js') }),
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|||||||
@@ -7,4 +7,9 @@ export default {
|
|||||||
data: '--config-override--',
|
data: '--config-override--',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
sizes: '--override-sizes--',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,12 +31,7 @@ export async function expectThrowsAsync(method, { errorMatch, errorMessage } = {
|
|||||||
export async function readOutput(
|
export async function readOutput(
|
||||||
cli,
|
cli,
|
||||||
fileName,
|
fileName,
|
||||||
{
|
{ stripToBody = false, stripStartEndWhitespace = true, type = 'build' } = {},
|
||||||
stripServiceWorker = false,
|
|
||||||
stripToBody = false,
|
|
||||||
stripStartEndWhitespace = true,
|
|
||||||
type = 'build',
|
|
||||||
} = {},
|
|
||||||
) {
|
) {
|
||||||
const outputDir = type === 'build' ? cli.config.outputDir : cli.config.outputDevDir;
|
const outputDir = type === 'build' ? cli.config.outputDir : cli.config.outputDevDir;
|
||||||
let text = await fs.promises.readFile(path.join(outputDir, fileName));
|
let text = await fs.promises.readFile(path.join(outputDir, fileName));
|
||||||
@@ -46,11 +41,6 @@ export async function readOutput(
|
|||||||
const bodyCloseTagStart = text.indexOf('</body>');
|
const bodyCloseTagStart = text.indexOf('</body>');
|
||||||
text = text.substring(bodyOpenTagEnd, bodyCloseTagStart);
|
text = text.substring(bodyOpenTagEnd, bodyCloseTagStart);
|
||||||
}
|
}
|
||||||
if (stripServiceWorker) {
|
|
||||||
const scriptOpenTagEnd = text.indexOf('<script inject-service-worker');
|
|
||||||
const scriptCloseTagStart = text.indexOf('</script>', scriptOpenTagEnd) + 9;
|
|
||||||
text = text.substring(0, scriptOpenTagEnd) + text.substring(scriptCloseTagStart);
|
|
||||||
}
|
|
||||||
if (stripStartEndWhitespace) {
|
if (stripStartEndWhitespace) {
|
||||||
text = text.trim();
|
text = text.trim();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,19 @@ describe('normalizeConfig', () => {
|
|||||||
setupEleventyComputedConfig: [],
|
setupEleventyComputedConfig: [],
|
||||||
setupCliPlugins: [],
|
setupCliPlugins: [],
|
||||||
presets: [],
|
presets: [],
|
||||||
|
serviceWorkerName: 'service-worker.js',
|
||||||
plugins: [
|
plugins: [
|
||||||
{ commands: ['start'] },
|
{ commands: ['start'] },
|
||||||
{ commands: ['build'] },
|
{ commands: ['build'] },
|
||||||
{ commands: ['start', 'build', 'lint'] },
|
{ commands: ['start', 'build', 'lint'] },
|
||||||
],
|
],
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
formats: ['avif', 'jpeg'],
|
||||||
|
sizes: '100vw',
|
||||||
|
widths: [600, 900, 1640],
|
||||||
|
},
|
||||||
|
},
|
||||||
inputDir: 'docs',
|
inputDir: 'docs',
|
||||||
outputDir: '_site',
|
outputDir: '_site',
|
||||||
});
|
});
|
||||||
@@ -76,6 +84,14 @@ describe('normalizeConfig', () => {
|
|||||||
setupCliPlugins: [],
|
setupCliPlugins: [],
|
||||||
setupEleventyComputedConfig: [],
|
setupEleventyComputedConfig: [],
|
||||||
presets: [],
|
presets: [],
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
formats: ['avif', 'jpeg'],
|
||||||
|
sizes: '100vw',
|
||||||
|
widths: [600, 900, 1640],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serviceWorkerName: 'service-worker.js',
|
||||||
plugins: [
|
plugins: [
|
||||||
{ commands: ['start'] },
|
{ commands: ['start'] },
|
||||||
{ commands: ['build'] },
|
{ commands: ['build'] },
|
||||||
@@ -108,6 +124,14 @@ describe('normalizeConfig', () => {
|
|||||||
setupCliPlugins: [],
|
setupCliPlugins: [],
|
||||||
setupEleventyComputedConfig: [],
|
setupEleventyComputedConfig: [],
|
||||||
presets: [],
|
presets: [],
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
formats: ['avif', 'jpeg'],
|
||||||
|
sizes: '--override-sizes--',
|
||||||
|
widths: [600, 900, 1640],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serviceWorkerName: 'service-worker.js',
|
||||||
plugins: [
|
plugins: [
|
||||||
{ commands: ['start'] },
|
{ commands: ['start'] },
|
||||||
{ commands: ['build'] },
|
{ commands: ['build'] },
|
||||||
@@ -143,6 +167,14 @@ describe('normalizeConfig', () => {
|
|||||||
setupCliPlugins: [],
|
setupCliPlugins: [],
|
||||||
setupEleventyComputedConfig: [],
|
setupEleventyComputedConfig: [],
|
||||||
presets: [],
|
presets: [],
|
||||||
|
imagePresets: {
|
||||||
|
responsive: {
|
||||||
|
formats: ['avif', 'jpeg'],
|
||||||
|
sizes: '100vw',
|
||||||
|
widths: [600, 900, 1640],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serviceWorkerName: 'service-worker.js',
|
||||||
plugins: [
|
plugins: [
|
||||||
{ commands: ['start'] },
|
{ commands: ['start'] },
|
||||||
{ commands: ['build'] },
|
{ commands: ['build'] },
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
**/*.njk
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
@@ -0,0 +1 @@
|
|||||||
|
module.exports = 'do-not-generate-a-social-media-image';
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
layout: layout-raw
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
export function myPreset() {
|
||||||
|
return {
|
||||||
|
path: path.resolve(__dirname),
|
||||||
|
adjustImagePresets: imagePresets => ({
|
||||||
|
...imagePresets,
|
||||||
|
responsive: {
|
||||||
|
...imagePresets.responsive,
|
||||||
|
widths: [30, 60],
|
||||||
|
formats: ['jpeg'],
|
||||||
|
sizes: '30px',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { myPreset } from './my-preset.js';
|
||||||
|
|
||||||
|
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
|
||||||
|
const config = {
|
||||||
|
presets: [myPreset()],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
12
packages/cli/types/main.d.ts
vendored
12
packages/cli/types/main.d.ts
vendored
@@ -17,15 +17,27 @@ interface RocketStartConfig {
|
|||||||
createSocialMediaImages?: boolean;
|
createSocialMediaImages?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ImageFormat = 'avif' | 'webp' | 'jpg' | 'png' | 'svg';
|
||||||
|
|
||||||
|
interface ImagePreset {
|
||||||
|
widths: number[];
|
||||||
|
formats: ImageFormat[];
|
||||||
|
sizes: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface RocketCliOptions {
|
export interface RocketCliOptions {
|
||||||
presets: Array<RocketPreset>;
|
presets: Array<RocketPreset>;
|
||||||
pathPrefix?: string;
|
pathPrefix?: string;
|
||||||
|
serviceWorkerName?: string;
|
||||||
inputDir: string;
|
inputDir: string;
|
||||||
outputDir: string;
|
outputDir: string;
|
||||||
emptyOutputDir?: boolean;
|
emptyOutputDir?: boolean;
|
||||||
absoluteBaseUrl?: string;
|
absoluteBaseUrl?: string;
|
||||||
watch: boolean;
|
watch: boolean;
|
||||||
createSocialMediaImages?: boolean;
|
createSocialMediaImages?: boolean;
|
||||||
|
imagePresets: {
|
||||||
|
[key: string]: ImagePreset;
|
||||||
|
};
|
||||||
|
|
||||||
start?: RocketStartConfig;
|
start?: RocketStartConfig;
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
},
|
},
|
||||||
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
|
||||||
"homepage": "https://rocket.modern-web.dev/",
|
"homepage": "https://rocket.modern-web.dev/",
|
||||||
"type": "module",
|
|
||||||
"main": "./dist/title.cjs",
|
"main": "./dist/title.cjs",
|
||||||
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./title": {
|
"./title": {
|
||||||
"require": "./dist/title.cjs",
|
"require": "./dist/title.cjs",
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @rocket/drawer
|
# @rocket/drawer
|
||||||
|
|
||||||
|
## 0.1.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 0b64116: Update @lion dependencies
|
||||||
|
|
||||||
## 0.1.2
|
## 0.1.2
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rocket/drawer",
|
"name": "@rocket/drawer",
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
"testing"
|
"testing"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lion/overlays": "^0.23.2",
|
"@lion/overlays": "^0.26.1",
|
||||||
"lit-element": "^2.4.0"
|
"lit-element": "^2.4.0"
|
||||||
},
|
},
|
||||||
"types": "dist-types/index.d.ts"
|
"types": "dist-types/index.d.ts"
|
||||||
|
|||||||
@@ -1,5 +1,32 @@
|
|||||||
# @rocket/eleventy-plugin-mdjs-unified
|
# @rocket/eleventy-plugin-mdjs-unified
|
||||||
|
|
||||||
|
## 0.5.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- eae2007: Update to mdjs version that uses lit 2 and renders stories to light dom
|
||||||
|
|
||||||
|
## 0.4.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 2b7f1ee: Add support for pathprefix
|
||||||
|
- Updated dependencies [2b7f1ee]
|
||||||
|
- @mdjs/core@0.7.1
|
||||||
|
|
||||||
|
## 0.4.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 2267e72: Write the mdjs JavaScript code to a file and load it from there instead of an inline script
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [a8e66d8]
|
||||||
|
- Updated dependencies [fe6a929]
|
||||||
|
- Updated dependencies [a8e66d8]
|
||||||
|
- @mdjs/core@0.7.0
|
||||||
|
|
||||||
## 0.3.1
|
## 0.3.1
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rocket/eleventy-plugin-mdjs-unified",
|
"name": "@rocket/eleventy-plugin-mdjs-unified",
|
||||||
"version": "0.3.1",
|
"version": "0.5.0",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"mdjs"
|
"mdjs"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mdjs/core": "^0.6.2",
|
"@mdjs/core": "^0.8.0",
|
||||||
"es-module-lexer": "^0.3.26",
|
"es-module-lexer": "^0.3.26",
|
||||||
"unist-util-visit": "^2.0.3"
|
"unist-util-visit": "^2.0.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
|
const path = require('path');
|
||||||
|
const slash = require('slash');
|
||||||
|
const fs = require('fs');
|
||||||
const { mdjsProcess } = require('@mdjs/core');
|
const { mdjsProcess } = require('@mdjs/core');
|
||||||
const visit = require('unist-util-visit');
|
const visit = require('unist-util-visit');
|
||||||
const { init, parse } = require('es-module-lexer');
|
const { init, parse } = require('es-module-lexer');
|
||||||
@@ -7,7 +10,7 @@ const { init, parse } = require('es-module-lexer');
|
|||||||
const { parseTitle } = require('@rocket/core/title');
|
const { parseTitle } = require('@rocket/core/title');
|
||||||
|
|
||||||
/** @typedef {import('@mdjs/core').MdjsProcessPlugin} MdjsProcessPlugin */
|
/** @typedef {import('@mdjs/core').MdjsProcessPlugin} MdjsProcessPlugin */
|
||||||
/** @typedef {import('../types/code').EleventPluginMdjsUnified} EleventPluginMdjsUnified */
|
/** @typedef {import('../types/code').EleventyPluginMdjsUnified} EleventyPluginMdjsUnified */
|
||||||
/** @typedef {import('../types/code').NodeChildren} NodeChildren */
|
/** @typedef {import('../types/code').NodeChildren} NodeChildren */
|
||||||
/** @typedef {import('../types/code').NodeElement} NodeElement */
|
/** @typedef {import('../types/code').NodeElement} NodeElement */
|
||||||
/** @typedef {import('unist').Node} Node */
|
/** @typedef {import('unist').Node} Node */
|
||||||
@@ -93,7 +96,7 @@ async function processImports(source, inputPath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {EleventPluginMdjsUnified} pluginOptions
|
* @param {EleventyPluginMdjsUnified} pluginOptions
|
||||||
*/
|
*/
|
||||||
function eleventyUnified(pluginOptions) {
|
function eleventyUnified(pluginOptions) {
|
||||||
/**
|
/**
|
||||||
@@ -119,8 +122,12 @@ function eleventyUnified(pluginOptions) {
|
|||||||
return plugins.map(plugin => {
|
return plugins.map(plugin => {
|
||||||
if (plugin.options) {
|
if (plugin.options) {
|
||||||
plugin.options.page = eleventySettings.page;
|
plugin.options.page = eleventySettings.page;
|
||||||
|
plugin.options.rocketConfig = eleventySettings.rocketConfig;
|
||||||
} else {
|
} else {
|
||||||
plugin.options = { page: eleventySettings.page };
|
plugin.options = {
|
||||||
|
page: eleventySettings.page,
|
||||||
|
rocketConfig: eleventySettings.rocketConfig,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return plugin;
|
return plugin;
|
||||||
});
|
});
|
||||||
@@ -139,10 +146,23 @@ function eleventyUnified(pluginOptions) {
|
|||||||
|
|
||||||
let code = result.html;
|
let code = result.html;
|
||||||
if (result.jsCode) {
|
if (result.jsCode) {
|
||||||
|
const newFolder = path.dirname(eleventySettings.page.outputPath);
|
||||||
|
const newName = path.join(newFolder, '__mdjs-stories.js');
|
||||||
|
await fs.promises.mkdir(newFolder, { recursive: true });
|
||||||
|
await fs.promises.writeFile(newName, result.jsCode, 'utf8');
|
||||||
|
|
||||||
|
let scriptUrl = eleventySettings.page.url;
|
||||||
|
if (
|
||||||
|
eleventySettings.rocketConfig &&
|
||||||
|
eleventySettings.rocketConfig.command === 'build' &&
|
||||||
|
eleventySettings.rocketConfig.pathPrefix
|
||||||
|
) {
|
||||||
|
scriptUrl = slash(
|
||||||
|
path.join(eleventySettings.rocketConfig.pathPrefix, eleventySettings.page.url),
|
||||||
|
);
|
||||||
|
}
|
||||||
code += `
|
code += `
|
||||||
<script type="module">
|
<script type="module" src="${scriptUrl}__mdjs-stories.js" mdjs-setup></script>
|
||||||
${result.jsCode}
|
|
||||||
</script>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
@@ -157,15 +177,15 @@ function eleventyUnified(pluginOptions) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {*} eleventyConfig
|
* @param {*} eleventyConfig
|
||||||
* @param {EleventPluginMdjsUnified} [pluginOptions]
|
* @param {EleventyPluginMdjsUnified} [pluginOptions]
|
||||||
*/
|
*/
|
||||||
function configFunction(eleventyConfig, pluginOptions = {}) {
|
function configFunction(eleventyConfig, pluginOptions = {}) {
|
||||||
eleventyConfig.setLibrary('md', eleventyUnified(pluginOptions));
|
eleventyConfig.setLibrary('md', eleventyUnified(pluginOptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
const eleventPluginMdjsUnified = {
|
const EleventyPluginMdjsUnified = {
|
||||||
initArguments: {},
|
initArguments: {},
|
||||||
configFunction,
|
configFunction,
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = eleventPluginMdjsUnified;
|
module.exports = EleventyPluginMdjsUnified;
|
||||||
|
|||||||
@@ -53,13 +53,12 @@ describe('eleventy-plugin-mdjs-unified', () => {
|
|||||||
|
|
||||||
it('renders markdown with javascript', async () => {
|
it('renders markdown with javascript', async () => {
|
||||||
const files = await renderEleventy('./test-node/fixtures/mdjs');
|
const files = await renderEleventy('./test-node/fixtures/mdjs');
|
||||||
expect(files).to.deep.equal([
|
|
||||||
{
|
expect(files.length).to.equal(1);
|
||||||
html:
|
expect(files[0].name).to.equal('first/index.html');
|
||||||
'<h1 id="first"><a aria-hidden="true" tabindex="-1" href="#first"><span class="icon icon-link"></span></a>First</h1>\n<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> foo <span class="token operator">=</span> <span class="token string">\'bar\'</span><span class="token punctuation">;</span>\n<span class="token keyword module">import</span> <span class="token punctuation">{</span> html <span class="token punctuation">}</span> <span class="token keyword module">from</span> <span class="token string">\'lit-html\'</span><span class="token punctuation">;</span>\n</code></pre>\n<mdjs-story mdjs-story-name="inline"></mdjs-story>\n<mdjs-preview mdjs-story-name="withBorder"></mdjs-preview>\n <script type="module">\n \nexport const inline = () => html` <p>main</p> `;\nexport const withBorder = () => html` <p>main</p> `;\nconst rootNode = document;\nconst stories = [{ key: \'inline\', story: inline, code: `<pre class="language-js"><code class="language-js"><span class="token keyword module">export</span> <span class="token keyword">const</span> <span class="token function-variable function">inline</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> html<span class="token template-string"><span class="token template-punctuation string">\\`</span><span class="token html language-html"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>main<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </span><span class="token template-punctuation string">\\`</span></span><span class="token punctuation">;</span>\n</code></pre>` }, { key: \'withBorder\', story: withBorder, code: `<pre class="language-js"><code class="language-js"><span class="token keyword module">export</span> <span class="token keyword">const</span> <span class="token function-variable function">withBorder</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> html<span class="token template-string"><span class="token template-punctuation string">\\`</span><span class="token html language-html"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>main<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </span><span class="token template-punctuation string">\\`</span></span><span class="token punctuation">;</span>\n</code></pre>` }];\nfor (const story of stories) {\n const storyEl = rootNode.querySelector(`[mdjs-story-name="${story.key}"]`);\n storyEl.codeHasHtml = true;\n storyEl.story = story.story;\n storyEl.code = story.code;\n};\nif (!customElements.get(\'mdjs-preview\')) { import(\'@mdjs/mdjs-preview/mdjs-preview.js\'); }\nif (!customElements.get(\'mdjs-story\')) { import(\'@mdjs/mdjs-story/mdjs-story.js\'); }\n </script>\n ',
|
|
||||||
name: 'first/index.html',
|
expect(files[0].html).to.include('<script type="module"');
|
||||||
},
|
expect(files[0].html).to.include('mdjs-setup>');
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rewrites relative import pathes', async () => {
|
it('rewrites relative import pathes', async () => {
|
||||||
@@ -67,7 +66,7 @@ describe('eleventy-plugin-mdjs-unified', () => {
|
|||||||
expect(files).to.deep.equal([
|
expect(files).to.deep.equal([
|
||||||
{
|
{
|
||||||
html:
|
html:
|
||||||
"<p>first</p>\n <script type=\"module\">\n import '../import-me.js';\nimport('../import-me-too.js');\n </script>\n ",
|
'<p>first</p>\n <script type="module" src="/first/__mdjs-stories.js" mdjs-setup></script>\n ',
|
||||||
name: 'first/index.html',
|
name: 'first/index.html',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -78,7 +77,7 @@ describe('eleventy-plugin-mdjs-unified', () => {
|
|||||||
expect(files).to.deep.equal([
|
expect(files).to.deep.equal([
|
||||||
{
|
{
|
||||||
html:
|
html:
|
||||||
"<p>first</p>\n <script type=\"module\">\n import '../../import-me.js';\nimport('../../import-me-too.js');\n </script>\n ",
|
'<p>first</p>\n <script type="module" src="/subpage/first/__mdjs-stories.js" mdjs-setup></script>\n ',
|
||||||
name: 'subpage/first/index.html',
|
name: 'subpage/first/index.html',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -89,7 +88,7 @@ describe('eleventy-plugin-mdjs-unified', () => {
|
|||||||
expect(files).to.deep.equal([
|
expect(files).to.deep.equal([
|
||||||
{
|
{
|
||||||
html:
|
html:
|
||||||
"<p>index</p>\n <script type=\"module\">\n import './import-me.js';\nimport('./import-me-too.js');\n </script>\n ",
|
'<p>index</p>\n <script type="module" src="/__mdjs-stories.js" mdjs-setup></script>\n ',
|
||||||
name: 'index.html',
|
name: 'index.html',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Node } from 'unist';
|
|||||||
|
|
||||||
export const setupUnifiedPluginsFn: (plugins: MdjsProcessPlugin[]) => MdjsProcessPlugin[];
|
export const setupUnifiedPluginsFn: (plugins: MdjsProcessPlugin[]) => MdjsProcessPlugin[];
|
||||||
|
|
||||||
export interface EleventPluginMdjsUnified {
|
export interface EleventyPluginMdjsUnified {
|
||||||
setupUnifiedPlugins?: setupUnifiedPluginsFn[];
|
setupUnifiedPlugins?: setupUnifiedPluginsFn[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,24 @@
|
|||||||
# @rocket/launch
|
# @rocket/launch
|
||||||
|
|
||||||
|
## 0.5.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 8bba4a8: Configure responsive image sizes to align with the launch preset breakpoints.
|
||||||
|
The set value is `sizes: '(min-width: 1024px) 820px, calc(100vw - 40px)'`.
|
||||||
|
|
||||||
|
## 0.4.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 2b7f1ee: Add support for pathprefix
|
||||||
|
|
||||||
|
## 0.4.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 81edf45: Reduce the amount of js files in the build by avoiding inline script tags
|
||||||
|
|
||||||
## 0.4.0
|
## 0.4.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rocket/launch",
|
"name": "@rocket/launch",
|
||||||
"version": "0.4.0",
|
"version": "0.5.0",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"preset"
|
"preset"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rocket/drawer": "^0.1.2",
|
"@rocket/drawer": "^0.1.3",
|
||||||
"@rocket/navigation": "^0.2.0"
|
"@rocket/navigation": "^0.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ hr {
|
|||||||
#content-wrapper .content-area,
|
#content-wrapper .content-area,
|
||||||
#main-header .content-area,
|
#main-header .content-area,
|
||||||
#main-footer .content-area {
|
#main-footer .content-area {
|
||||||
padding: 0 30px;
|
padding: 0 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#content-wrapper .content-area {
|
#content-wrapper .content-area {
|
||||||
|
|||||||
@@ -463,9 +463,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.markdown-body img {
|
.markdown-body img {
|
||||||
/* background-color: #fff; */
|
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1 @@
|
|||||||
{#
|
<script type="module" src="{{ '/_assets/scripts/init-navigation.js' | asset | url }}"></script>
|
||||||
src leads to the file not being included/executed? bug in rollup-plugin-html?
|
|
||||||
<script type="module" src="{{ '/_assets/scripts/init-navigation.js' | asset }}"></script>
|
|
||||||
#}
|
|
||||||
<script type="module">
|
|
||||||
import '@rocket/navigation/rocket-navigation.js';
|
|
||||||
import '@rocket/drawer/rocket-drawer.js';
|
|
||||||
const drawer = document.querySelector('#sidebar');
|
|
||||||
|
|
||||||
// Toggle button
|
|
||||||
const triggers = document.querySelectorAll('[data-action="trigger-mobile-menu"]');
|
|
||||||
for (const trigger of [...triggers]) {
|
|
||||||
trigger.addEventListener('click', function () {
|
|
||||||
drawer.opened = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<meta property="og:site_name" content="{{ site.name }}"/>
|
<meta property="og:site_name" content="{{ site.name }}"/>
|
||||||
<meta property="og:type" content="website"/>
|
<meta property="og:type" content="website"/>
|
||||||
|
|
||||||
<meta property="og:image" content="{{ socialMediaImage }}"/>
|
<meta property="og:image" content="{{ socialMediaImage | url }}"/>
|
||||||
<meta property="og:url" content="{{ page.url }}"/>
|
<meta property="og:url" content="{{ page.url | url }}"/>
|
||||||
|
|
||||||
<meta name="twitter:card" content="summary_large_image"/>
|
<meta name="twitter:card" content="summary_large_image"/>
|
||||||
|
|||||||
@@ -52,5 +52,13 @@ export function rocketLaunch() {
|
|||||||
setupEleventyComputedConfig: [
|
setupEleventyComputedConfig: [
|
||||||
adjustPluginOptions('layout', { defaultLayout: 'layout-sidebar' }),
|
adjustPluginOptions('layout', { defaultLayout: 'layout-sidebar' }),
|
||||||
],
|
],
|
||||||
|
adjustImagePresets: imagePresets => ({
|
||||||
|
...imagePresets,
|
||||||
|
responsive: {
|
||||||
|
...imagePresets.responsive,
|
||||||
|
widths: [600, 900, 1640],
|
||||||
|
sizes: '(min-width: 1024px) 820px, calc(100vw - 40px)',
|
||||||
|
},
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,19 +208,13 @@ describe('RocketLaunch preset', () => {
|
|||||||
' </div>',
|
' </div>',
|
||||||
' </footer>',
|
' </footer>',
|
||||||
'',
|
'',
|
||||||
' <script type="module">',
|
' <script type="module" src="/_merged_assets/scripts/init-navigation.js"></script>',
|
||||||
' import "@rocket/navigation/rocket-navigation.js";',
|
|
||||||
' import "@rocket/drawer/rocket-drawer.js";',
|
|
||||||
' const drawer = document.querySelector("#sidebar");',
|
|
||||||
'',
|
'',
|
||||||
' // Toggle button',
|
' <script',
|
||||||
` const triggers = document.querySelectorAll('[data-action="trigger-mobile-menu"]');`,
|
' type="module"',
|
||||||
' for (const trigger of [...triggers]) {',
|
' inject-service-worker=""',
|
||||||
' trigger.addEventListener("click", function () {',
|
' src="/_merged_assets/scripts/registerServiceWorker.js"',
|
||||||
' drawer.opened = true;',
|
' ></script>',
|
||||||
' });',
|
|
||||||
' }',
|
|
||||||
' </script>',
|
|
||||||
' </body>',
|
' </body>',
|
||||||
'</html>',
|
'</html>',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
@@ -443,19 +437,13 @@ describe('RocketLaunch preset', () => {
|
|||||||
' </div>',
|
' </div>',
|
||||||
' </footer>',
|
' </footer>',
|
||||||
'',
|
'',
|
||||||
' <script type="module">',
|
' <script type="module" src="/_merged_assets/scripts/init-navigation.js"></script>',
|
||||||
' import "@rocket/navigation/rocket-navigation.js";',
|
|
||||||
' import "@rocket/drawer/rocket-drawer.js";',
|
|
||||||
' const drawer = document.querySelector("#sidebar");',
|
|
||||||
'',
|
'',
|
||||||
' // Toggle button',
|
' <script',
|
||||||
` const triggers = document.querySelectorAll('[data-action="trigger-mobile-menu"]');`,
|
' type="module"',
|
||||||
' for (const trigger of [...triggers]) {',
|
' inject-service-worker=""',
|
||||||
' trigger.addEventListener("click", function () {',
|
' src="/_merged_assets/scripts/registerServiceWorker.js"',
|
||||||
' drawer.opened = true;',
|
' ></script>',
|
||||||
' });',
|
|
||||||
' }',
|
|
||||||
' </script>',
|
|
||||||
' </body>',
|
' </body>',
|
||||||
'</html>',
|
'</html>',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
|
|||||||
@@ -1,5 +1,87 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 814b5d2: **BREAKING CHANGE** Stories of `story` and `preview-story` are now rendered to light dom instead of shadow dom to allow usage of a scoped registry for the internal dom
|
||||||
|
|
||||||
|
```js
|
||||||
|
export const story = html`
|
||||||
|
<p>my story</p>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- before -->
|
||||||
|
<mdjs-story>
|
||||||
|
#shadow-root (open)
|
||||||
|
<p>my story</p>
|
||||||
|
</mdjs-story>
|
||||||
|
|
||||||
|
<!-- after -->
|
||||||
|
<mdjs-story>
|
||||||
|
<p>my story</p>
|
||||||
|
</mdjs-story>
|
||||||
|
```
|
||||||
|
|
||||||
|
- e1e96ac: **BREAKING CHANGE** The default renderer for `story` and `preview-story` updated to [lit](https://lit.dev/) 2
|
||||||
|
|
||||||
|
If your main lit-html version is 1.x be sure to import html for your story rendering from `@mdjs/mdjs-preview`.
|
||||||
|
|
||||||
|
````md
|
||||||
|
```js script
|
||||||
|
import { html } from '@mdjs/mdjs-preview';
|
||||||
|
```
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const foo = () =>
|
||||||
|
html`
|
||||||
|
<demo-element></demo-element>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [e1e96ac]
|
||||||
|
- Updated dependencies [814b5d2]
|
||||||
|
- Updated dependencies [814b5d2]
|
||||||
|
- Updated dependencies [e1e96ac]
|
||||||
|
- @mdjs/mdjs-preview@0.5.0
|
||||||
|
- @mdjs/mdjs-story@0.3.0
|
||||||
|
|
||||||
|
## 0.7.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- ce9b12e: Support importing via es module
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { mdjsProcess } = from '@mdjs/core';
|
||||||
|
```
|
||||||
|
|
||||||
|
## 0.7.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 2b7f1ee: Add support for pathprefix
|
||||||
|
|
||||||
|
## 0.7.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- a8e66d8: Extract building of the JavaScript setup code into a unified plugin called mdjsSetupCode
|
||||||
|
- fe6a929: For the story preview keep the original code block around to get code highlighting from the main document. This enables styling and reduces the code complexity.
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- a8e66d8: You can provide a highlightCode function to the mdjsSetupCode unified plugin
|
||||||
|
- Updated dependencies [edb1abf]
|
||||||
|
- Updated dependencies [604a80e]
|
||||||
|
- @mdjs/mdjs-preview@0.4.0
|
||||||
|
- @mdjs/mdjs-story@0.2.0
|
||||||
|
|
||||||
## 0.6.2
|
## 0.6.2
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mdjs/core",
|
"name": "@mdjs/core",
|
||||||
"version": "0.6.2",
|
"version": "0.8.0",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"*.d.ts",
|
"*.d.ts",
|
||||||
"*.js",
|
"*.js",
|
||||||
|
"*.mjs",
|
||||||
"dist-types",
|
"dist-types",
|
||||||
"src",
|
"src",
|
||||||
"types"
|
"types"
|
||||||
@@ -43,12 +44,12 @@
|
|||||||
"remark"
|
"remark"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mdjs/mdjs-preview": "^0.3.1",
|
"@mdjs/mdjs-preview": "^0.5.0",
|
||||||
"@mdjs/mdjs-story": "^0.1.1",
|
"@mdjs/mdjs-story": "^0.3.0",
|
||||||
"@types/unist": "^2.0.3",
|
"@types/unist": "^2.0.3",
|
||||||
"es-module-lexer": "^0.3.26",
|
"es-module-lexer": "^0.3.26",
|
||||||
"github-markdown-css": "^4.0.0",
|
"github-markdown-css": "^4.0.0",
|
||||||
"plugins-manager": "^0.2.0",
|
"plugins-manager": "^0.2.2",
|
||||||
"rehype-autolink-headings": "^5.0.1",
|
"rehype-autolink-headings": "^5.0.1",
|
||||||
"rehype-prism-template": "^0.4.1",
|
"rehype-prism-template": "^0.4.1",
|
||||||
"rehype-raw": "^5.0.0",
|
"rehype-raw": "^5.0.0",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ const { executeSetupFunctions } = require('plugins-manager');
|
|||||||
|
|
||||||
const { mdjsParse } = require('./mdjsParse.js');
|
const { mdjsParse } = require('./mdjsParse.js');
|
||||||
const { mdjsStoryParse } = require('./mdjsStoryParse.js');
|
const { mdjsStoryParse } = require('./mdjsStoryParse.js');
|
||||||
|
const { mdjsSetupCode } = require('./mdjsSetupCode.js');
|
||||||
|
|
||||||
/** @type {MdjsProcessPlugin[]} */
|
/** @type {MdjsProcessPlugin[]} */
|
||||||
const defaultMetaPlugins = [
|
const defaultMetaPlugins = [
|
||||||
@@ -25,6 +26,7 @@ const defaultMetaPlugins = [
|
|||||||
{ name: 'gfm', plugin: gfm },
|
{ name: 'gfm', plugin: gfm },
|
||||||
{ name: 'mdjsParse', plugin: mdjsParse },
|
{ name: 'mdjsParse', plugin: mdjsParse },
|
||||||
{ name: 'mdjsStoryParse', plugin: mdjsStoryParse },
|
{ name: 'mdjsStoryParse', plugin: mdjsStoryParse },
|
||||||
|
{ name: 'mdjsSetupCode', plugin: mdjsSetupCode },
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
{ name: 'remark2rehype', plugin: remark2rehype, options: { allowDangerousHtml: true } },
|
{ name: 'remark2rehype', plugin: remark2rehype, options: { allowDangerousHtml: true } },
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -50,29 +52,15 @@ const defaultMetaPlugins = [
|
|||||||
* @param {function[]} [options.setupUnifiedPlugins]
|
* @param {function[]} [options.setupUnifiedPlugins]
|
||||||
* @param {MdjsProcessPlugin[]} [options.plugins] deprecated option use setupUnifiedPlugins instead
|
* @param {MdjsProcessPlugin[]} [options.plugins] deprecated option use setupUnifiedPlugins instead
|
||||||
*/
|
*/
|
||||||
async function mdjsProcess(
|
async function mdjsProcess(mdjs, { setupUnifiedPlugins = [] } = {}) {
|
||||||
mdjs,
|
|
||||||
{ rootNodeQueryCode = 'document', setupUnifiedPlugins = [] } = {},
|
|
||||||
) {
|
|
||||||
const parser = unified();
|
const parser = unified();
|
||||||
|
|
||||||
const metaPlugins = executeSetupFunctions(setupUnifiedPlugins, defaultMetaPlugins);
|
const metaPlugins = executeSetupFunctions(setupUnifiedPlugins, defaultMetaPlugins);
|
||||||
|
|
||||||
// @ts-ignore
|
/**
|
||||||
for (const pluginObj of metaPlugins) {
|
* @param {string} code
|
||||||
parser.use(pluginObj.plugin, pluginObj.options);
|
*/
|
||||||
}
|
async function highlightCode(code) {
|
||||||
|
|
||||||
/** @type {unknown} */
|
|
||||||
const parseResult = await parser.process(mdjs);
|
|
||||||
const result = /** @type {ParseResult} */ (parseResult);
|
|
||||||
|
|
||||||
const { stories, jsCode } = result.data;
|
|
||||||
let fullJsCode = jsCode;
|
|
||||||
|
|
||||||
if (stories && stories.length > 0) {
|
|
||||||
const storiesCode = stories.map(story => story.code).join('\n');
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const codePlugins = metaPlugins.filter(pluginObj =>
|
const codePlugins = metaPlugins.filter(pluginObj =>
|
||||||
['markdown', 'remark2rehype', 'rehypePrism', 'htmlStringify'].includes(pluginObj.name),
|
['markdown', 'remark2rehype', 'rehypePrism', 'htmlStringify'].includes(pluginObj.name),
|
||||||
@@ -82,46 +70,30 @@ async function mdjsProcess(
|
|||||||
for (const pluginObj of codePlugins) {
|
for (const pluginObj of codePlugins) {
|
||||||
codeParser.use(pluginObj.plugin, pluginObj.options);
|
codeParser.use(pluginObj.plugin, pluginObj.options);
|
||||||
}
|
}
|
||||||
|
const codeResult = await codeParser.process(code);
|
||||||
const invokeStoriesCode = [];
|
return codeResult.contents;
|
||||||
for (const story of stories) {
|
|
||||||
let code = '';
|
|
||||||
switch (story.type) {
|
|
||||||
case 'html':
|
|
||||||
code = `\`\`\`html\n${story.code.split('`')[1]}\n\`\`\``;
|
|
||||||
break;
|
|
||||||
case 'js':
|
|
||||||
code = `\`\`\`js\n${story.code}\n\`\`\``;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const codeResult = await codeParser.process(code);
|
|
||||||
const highlightedCode = /** @type {string} */ (codeResult.contents)
|
|
||||||
.replace(/`/g, '\\`')
|
|
||||||
.replace(/\$/g, '\\$');
|
|
||||||
invokeStoriesCode.push(
|
|
||||||
`{ key: '${story.key}', story: ${story.key}, code: \`${highlightedCode}\` }`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fullJsCode = [
|
|
||||||
jsCode,
|
|
||||||
storiesCode,
|
|
||||||
`const rootNode = ${rootNodeQueryCode};`,
|
|
||||||
`const stories = [${invokeStoriesCode.join(', ')}];`,
|
|
||||||
`for (const story of stories) {`,
|
|
||||||
// eslint-disable-next-line no-template-curly-in-string
|
|
||||||
' const storyEl = rootNode.querySelector(`[mdjs-story-name="${story.key}"]`);',
|
|
||||||
` storyEl.codeHasHtml = true;`,
|
|
||||||
` storyEl.story = story.story;`,
|
|
||||||
` storyEl.code = story.code;`,
|
|
||||||
`};`,
|
|
||||||
`if (!customElements.get('mdjs-preview')) { import('@mdjs/mdjs-preview/mdjs-preview.js'); }`,
|
|
||||||
`if (!customElements.get('mdjs-story')) { import('@mdjs/mdjs-story/mdjs-story.js'); }`,
|
|
||||||
].join('\n');
|
|
||||||
}
|
}
|
||||||
return { stories, jsCode: fullJsCode, html: result.contents };
|
|
||||||
|
// @ts-ignore
|
||||||
|
for (const pluginObj of metaPlugins) {
|
||||||
|
if (pluginObj.name === 'mdjsSetupCode') {
|
||||||
|
if (pluginObj.options && !pluginObj.options.highlightCode) {
|
||||||
|
pluginObj.options.highlightCode = highlightCode;
|
||||||
|
}
|
||||||
|
if (!pluginObj.options) {
|
||||||
|
pluginObj.options = { highlightCode };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parser.use(pluginObj.plugin, pluginObj.options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {unknown} */
|
||||||
|
const parseResult = await parser.process(mdjs);
|
||||||
|
const result = /** @type {ParseResult} */ (parseResult);
|
||||||
|
|
||||||
|
const { stories, setupJsCode } = result.data;
|
||||||
|
|
||||||
|
return { stories, jsCode: setupJsCode, html: result.contents };
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
92
packages/mdjs-core/src/mdjsSetupCode.js
Normal file
92
packages/mdjs-core/src/mdjsSetupCode.js
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const slash = require('slash');
|
||||||
|
|
||||||
|
/** @typedef {import('vfile').VFileOptions} VFileOptions */
|
||||||
|
/** @typedef {import('unist').Node} Node */
|
||||||
|
/** @typedef {import('@mdjs/core/types/code').Story} Story */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} simulationSettings
|
||||||
|
* @property {string} [simulatorUrl]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} rocketConfig
|
||||||
|
* @property {string} [pathPrefix]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} options
|
||||||
|
* @param {string} [options.rootNodeQueryCode]
|
||||||
|
* @param {simulationSettings} [options.simulationSettings]
|
||||||
|
* @param {rocketConfig} [options.rocketConfig]
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function mdjsSetupCode({
|
||||||
|
rootNodeQueryCode = 'document',
|
||||||
|
simulationSettings = {},
|
||||||
|
rocketConfig = {},
|
||||||
|
} = {}) {
|
||||||
|
if (rocketConfig && rocketConfig.pathPrefix) {
|
||||||
|
if (simulationSettings && simulationSettings.simulatorUrl) {
|
||||||
|
const { simulatorUrl } = simulationSettings;
|
||||||
|
if (simulatorUrl[0] === '/' && !simulatorUrl.startsWith(rocketConfig.pathPrefix)) {
|
||||||
|
simulationSettings.simulatorUrl = slash(
|
||||||
|
path.join(rocketConfig.pathPrefix, simulationSettings.simulatorUrl),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Node} tree
|
||||||
|
* @param {VFileOptions} file
|
||||||
|
*/
|
||||||
|
async function transformer(tree, file) {
|
||||||
|
const { stories, jsCode } = file.data;
|
||||||
|
|
||||||
|
file.data.setupJsCode = jsCode;
|
||||||
|
|
||||||
|
if (stories && stories.length > 0) {
|
||||||
|
const storiesCode = stories.map(/** @param {Story} story */ story => story.code).join('\n');
|
||||||
|
|
||||||
|
const invokeStoriesCode = [];
|
||||||
|
for (const story of stories) {
|
||||||
|
invokeStoriesCode.push(`{ key: '${story.key}', story: ${story.key} }`);
|
||||||
|
}
|
||||||
|
|
||||||
|
file.data.setupJsCode = [
|
||||||
|
'/** script code **/',
|
||||||
|
jsCode,
|
||||||
|
'/** stories code **/',
|
||||||
|
storiesCode,
|
||||||
|
'/** stories setup code **/',
|
||||||
|
`const rootNode = ${rootNodeQueryCode};`,
|
||||||
|
`const stories = [${invokeStoriesCode.join(', ')}];`,
|
||||||
|
'let needsMdjsElements = false;',
|
||||||
|
`for (const story of stories) {`,
|
||||||
|
// eslint-disable-next-line no-template-curly-in-string
|
||||||
|
' const storyEl = rootNode.querySelector(`[mdjs-story-name="${story.key}"]`);',
|
||||||
|
' if (storyEl) {',
|
||||||
|
` storyEl.story = story.story;`,
|
||||||
|
` storyEl.key = story.key;`,
|
||||||
|
` needsMdjsElements = true;`,
|
||||||
|
` Object.assign(storyEl, ${JSON.stringify(simulationSettings)});`,
|
||||||
|
' }',
|
||||||
|
`};`,
|
||||||
|
'if (needsMdjsElements) {',
|
||||||
|
` if (!customElements.get('mdjs-preview')) { import('@mdjs/mdjs-preview/define'); }`,
|
||||||
|
` if (!customElements.get('mdjs-story')) { import('@mdjs/mdjs-story/define'); }`,
|
||||||
|
'}',
|
||||||
|
].join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
return transformer;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mdjsSetupCode,
|
||||||
|
};
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
/** @typedef {import('@mdjs/core/types/code').StoryTypes} StoryTypes */
|
/** @typedef {import('@mdjs/core/types/code').StoryTypes} StoryTypes */
|
||||||
/** @typedef {(name: string) => string} TagFunction */
|
/** @typedef {(name: string) => string} TagFunction */
|
||||||
/** @typedef {import('unist').Node} UnistNode */
|
/** @typedef {import('unist').Node} UnistNode */
|
||||||
|
/** @typedef {import('unist').Parent} UnistParent */
|
||||||
/** @typedef {import('vfile').VFileOptions} VFileOptions */
|
/** @typedef {import('vfile').VFileOptions} VFileOptions */
|
||||||
|
|
||||||
const visit = require('unist-util-visit');
|
const visit = require('unist-util-visit');
|
||||||
@@ -40,7 +41,7 @@ function defaultStoryTag(name) {
|
|||||||
* @param {string} name
|
* @param {string} name
|
||||||
*/
|
*/
|
||||||
function defaultPreviewStoryTag(name) {
|
function defaultPreviewStoryTag(name) {
|
||||||
return `<mdjs-preview mdjs-story-name="${name}"></mdjs-preview>`;
|
return `<mdjs-preview mdjs-story-name="${name}">[[CODE SLOT]]</mdjs-preview>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,14 +56,16 @@ function mdjsStoryParse({
|
|||||||
} = {}) {
|
} = {}) {
|
||||||
/** @type {Story[]} */
|
/** @type {Story[]} */
|
||||||
const stories = [];
|
const stories = [];
|
||||||
let index = 0;
|
let htmlIndex = 0;
|
||||||
|
|
||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {UnistNode} node
|
* @param {UnistNode} node
|
||||||
|
* @param {number} index
|
||||||
|
* @param {UnistParent} parent
|
||||||
*/
|
*/
|
||||||
const nodeCodeVisitor = node => {
|
const nodeCodeVisitor = (node, index, parent) => {
|
||||||
if (node.lang === 'js' && node.meta === 'story' && typeof node.value === 'string') {
|
if (node.lang === 'js' && node.meta === 'story' && typeof node.value === 'string') {
|
||||||
const storyData = extractStoryData(node.value);
|
const storyData = extractStoryData(node.value);
|
||||||
node.type = 'html';
|
node.type = 'html';
|
||||||
@@ -71,30 +74,65 @@ function mdjsStoryParse({
|
|||||||
}
|
}
|
||||||
if (node.lang === 'js' && node.meta === 'preview-story' && typeof node.value === 'string') {
|
if (node.lang === 'js' && node.meta === 'preview-story' && typeof node.value === 'string') {
|
||||||
const storyData = extractStoryData(node.value);
|
const storyData = extractStoryData(node.value);
|
||||||
node.type = 'html';
|
const newValue = previewStoryTag(storyData.name);
|
||||||
node.value = previewStoryTag(storyData.name);
|
if (newValue.includes('[[CODE SLOT]]')) {
|
||||||
|
const tagParts = newValue.split('[[CODE SLOT]]');
|
||||||
|
node = {
|
||||||
|
type: 'root',
|
||||||
|
children: [
|
||||||
|
{ type: 'html', value: tagParts[0] },
|
||||||
|
{ type: 'text', value: '\n\n' },
|
||||||
|
node,
|
||||||
|
{ type: 'text', value: '\n\n' },
|
||||||
|
{ type: 'html', value: tagParts[1] },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
parent.children.splice(index, 1, node);
|
||||||
|
} else {
|
||||||
|
node.type = 'html';
|
||||||
|
node.value = previewStoryTag(storyData.name);
|
||||||
|
}
|
||||||
|
|
||||||
stories.push(storyData);
|
stories.push(storyData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.lang === 'html' && node.meta === 'story') {
|
if (node.lang === 'html' && node.meta === 'story') {
|
||||||
const storyData = extractStoryData(
|
const storyData = extractStoryData(
|
||||||
`export const HtmlStory${index} = () => html\`${node.value}\`;`,
|
`export const HtmlStory${htmlIndex} = () => html\`${node.value}\`;`,
|
||||||
{ type: 'html' },
|
{ type: 'html' },
|
||||||
);
|
);
|
||||||
node.type = 'html';
|
node.type = 'html';
|
||||||
node.value = storyTag(storyData.name);
|
node.value = storyTag(storyData.name);
|
||||||
stories.push(storyData);
|
stories.push(storyData);
|
||||||
index += 1;
|
htmlIndex += 1;
|
||||||
}
|
}
|
||||||
if (node.lang === 'html' && node.meta === 'preview-story') {
|
if (node.lang === 'html' && node.meta === 'preview-story') {
|
||||||
const storyData = extractStoryData(
|
const storyData = extractStoryData(
|
||||||
`export const HtmlStory${index} = () => html\`${node.value}\`;`,
|
`export const HtmlStory${htmlIndex} = () => html\`${node.value}\`;`,
|
||||||
{ type: 'html' },
|
{ type: 'html' },
|
||||||
);
|
);
|
||||||
node.type = 'html';
|
|
||||||
node.value = previewStoryTag(storyData.name);
|
const newValue = previewStoryTag(storyData.name);
|
||||||
|
if (newValue.includes('[[CODE SLOT]]')) {
|
||||||
|
const tagParts = newValue.split('[[CODE SLOT]]');
|
||||||
|
node = {
|
||||||
|
type: 'root',
|
||||||
|
children: [
|
||||||
|
{ type: 'html', value: tagParts[0] },
|
||||||
|
{ type: 'text', value: '\n\n' },
|
||||||
|
node,
|
||||||
|
{ type: 'text', value: '\n\n' },
|
||||||
|
{ type: 'html', value: tagParts[1] },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
parent.children.splice(index, 1, node);
|
||||||
|
} else {
|
||||||
|
node.type = 'html';
|
||||||
|
node.value = previewStoryTag(storyData.name);
|
||||||
|
}
|
||||||
|
|
||||||
stories.push(storyData);
|
stories.push(storyData);
|
||||||
index += 1;
|
htmlIndex += 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,16 @@ describe('Integration', () => {
|
|||||||
'<pre><code class="language-js">const foo = 1;',
|
'<pre><code class="language-js">const foo = 1;',
|
||||||
'</code></pre>',
|
'</code></pre>',
|
||||||
'<mdjs-story mdjs-story-name="fooStory"></mdjs-story>',
|
'<mdjs-story mdjs-story-name="fooStory"></mdjs-story>',
|
||||||
'<mdjs-preview mdjs-story-name="fooPreviewStory"></mdjs-preview>',
|
'<mdjs-preview mdjs-story-name="fooPreviewStory">',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'<pre><code class="language-js">export const fooPreviewStory = () => {}',
|
||||||
|
'</code></pre>',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'</mdjs-preview>',
|
||||||
];
|
];
|
||||||
|
|
||||||
const parser = unified()
|
const parser = unified()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable no-template-curly-in-string */
|
/* eslint-disable no-template-curly-in-string */
|
||||||
|
|
||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
|
const { adjustPluginOptions } = require('plugins-manager');
|
||||||
const { mdjsProcess } = require('../src/mdjsProcess.js');
|
const { mdjsProcess } = require('../src/mdjsProcess.js');
|
||||||
|
|
||||||
const { expect } = chai;
|
const { expect } = chai;
|
||||||
@@ -28,27 +29,44 @@ describe('mdjsProcess', () => {
|
|||||||
'<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> foo <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>',
|
'<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> foo <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>',
|
||||||
'</code></pre>',
|
'</code></pre>',
|
||||||
'<mdjs-story mdjs-story-name="fooStory"></mdjs-story>',
|
'<mdjs-story mdjs-story-name="fooStory"></mdjs-story>',
|
||||||
'<mdjs-preview mdjs-story-name="fooPreviewStory"></mdjs-preview>',
|
'<mdjs-preview mdjs-story-name="fooPreviewStory">',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'<pre class="language-js"><code class="language-js"><span class="token keyword module">export</span> <span class="token keyword">const</span> <span class="token function-variable function">fooPreviewStory</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span>',
|
||||||
|
'</code></pre>',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'</mdjs-preview>',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
const expectedJsCode = [
|
const expectedJsCode = [
|
||||||
|
'/** script code **/',
|
||||||
'const bar = 2;',
|
'const bar = 2;',
|
||||||
|
'/** stories code **/',
|
||||||
'export const fooStory = () => {}',
|
'export const fooStory = () => {}',
|
||||||
'export const fooPreviewStory = () => {}',
|
'export const fooPreviewStory = () => {}',
|
||||||
|
'/** stories setup code **/',
|
||||||
'const rootNode = document;',
|
'const rootNode = document;',
|
||||||
`const stories = [{ key: 'fooStory', story: fooStory, code: \`<pre class="language-js"><code class="language-js"><span class="token keyword module">export</span> <span class="token keyword">const</span> <span class="token function-variable function">fooStory</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span>`,
|
`const stories = [{ key: 'fooStory', story: fooStory }, { key: 'fooPreviewStory', story: fooPreviewStory }];`,
|
||||||
`</code></pre>\` }, { key: 'fooPreviewStory', story: fooPreviewStory, code: \`<pre class="language-js"><code class="language-js"><span class="token keyword module">export</span> <span class="token keyword">const</span> <span class="token function-variable function">fooPreviewStory</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span>`,
|
'let needsMdjsElements = false;',
|
||||||
`</code></pre>\` }];`,
|
|
||||||
'for (const story of stories) {',
|
'for (const story of stories) {',
|
||||||
' const storyEl = rootNode.querySelector(`[mdjs-story-name="${story.key}"]`);',
|
' const storyEl = rootNode.querySelector(`[mdjs-story-name="${story.key}"]`);',
|
||||||
' storyEl.codeHasHtml = true;',
|
' if (storyEl) {',
|
||||||
' storyEl.story = story.story;',
|
' storyEl.story = story.story;',
|
||||||
' storyEl.code = story.code;',
|
' storyEl.key = story.key;',
|
||||||
|
' needsMdjsElements = true;',
|
||||||
|
' Object.assign(storyEl, {});',
|
||||||
|
' }',
|
||||||
'};',
|
'};',
|
||||||
`if (!customElements.get('mdjs-preview')) { import('@mdjs/mdjs-preview/mdjs-preview.js'); }`,
|
'if (needsMdjsElements) {',
|
||||||
`if (!customElements.get('mdjs-story')) { import('@mdjs/mdjs-story/mdjs-story.js'); }`,
|
` if (!customElements.get('mdjs-preview')) { import('@mdjs/mdjs-preview/define'); }`,
|
||||||
|
` if (!customElements.get('mdjs-story')) { import('@mdjs/mdjs-story/define'); }`,
|
||||||
|
'}',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
const result = await mdjsProcess(input);
|
const result = await mdjsProcess(input);
|
||||||
|
|
||||||
expect(result.html).to.equal(expected);
|
expect(result.html).to.equal(expected);
|
||||||
expect(result.jsCode).to.equal(expectedJsCode);
|
expect(result.jsCode).to.equal(expectedJsCode);
|
||||||
});
|
});
|
||||||
@@ -150,4 +168,45 @@ describe('mdjsProcess', () => {
|
|||||||
const result = await mdjsProcess(input);
|
const result = await mdjsProcess(input);
|
||||||
expect(result.html.trim()).to.equal(expected);
|
expect(result.html.trim()).to.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can adjust languages for story preview', async () => {
|
||||||
|
const input = [
|
||||||
|
'Intro',
|
||||||
|
'```js preview-story',
|
||||||
|
'export const fooPreviewStory = () => {}',
|
||||||
|
'```',
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
const expected = [
|
||||||
|
`/** script code **/`,
|
||||||
|
``,
|
||||||
|
`/** stories code **/`,
|
||||||
|
`export const fooPreviewStory = () => {}`,
|
||||||
|
`/** stories setup code **/`,
|
||||||
|
`const rootNode = document;`,
|
||||||
|
`const stories = [{ key: 'fooPreviewStory', story: fooPreviewStory }];`,
|
||||||
|
`let needsMdjsElements = false;`,
|
||||||
|
`for (const story of stories) {`,
|
||||||
|
' const storyEl = rootNode.querySelector(`[mdjs-story-name="${story.key}"]`);',
|
||||||
|
` if (storyEl) {`,
|
||||||
|
` storyEl.story = story.story;`,
|
||||||
|
` storyEl.key = story.key;`,
|
||||||
|
` needsMdjsElements = true;`,
|
||||||
|
' Object.assign(storyEl, {"languages":[{"key":"en","name":"English"}]});',
|
||||||
|
` }`,
|
||||||
|
`};`,
|
||||||
|
`if (needsMdjsElements) {`,
|
||||||
|
` if (!customElements.get('mdjs-preview')) { import('@mdjs/mdjs-preview/define'); }`,
|
||||||
|
` if (!customElements.get('mdjs-story')) { import('@mdjs/mdjs-story/define'); }`,
|
||||||
|
`}`,
|
||||||
|
].join('\n');
|
||||||
|
const result = await mdjsProcess(input, {
|
||||||
|
setupUnifiedPlugins: [
|
||||||
|
adjustPluginOptions('mdjsSetupCode', {
|
||||||
|
simulationSettings: { languages: [{ key: 'en', name: 'English' }] },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(result.jsCode.trim()).to.equal(expected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ describe('mdjsParse', () => {
|
|||||||
expect(/** @type {MDJSVFileData} */ (result.data).jsCode).to.equal('const bar = 22;');
|
expect(/** @type {MDJSVFileData} */ (result.data).jsCode).to.equal('const bar = 22;');
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: fix this bug
|
// TODO: fix this bug - maybe something in unified itself 🤔
|
||||||
it.skip('handling only "js script" code blocks', async () => {
|
it.skip('handling only "js script" code blocks', async () => {
|
||||||
const input = [
|
const input = [
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -37,9 +37,27 @@ describe('mdjsStoryParse', () => {
|
|||||||
'<pre><code class="language-js">const foo = 1;',
|
'<pre><code class="language-js">const foo = 1;',
|
||||||
'</code></pre>',
|
'</code></pre>',
|
||||||
'<mdjs-story mdjs-story-name="fooStory"></mdjs-story>',
|
'<mdjs-story mdjs-story-name="fooStory"></mdjs-story>',
|
||||||
'<mdjs-preview mdjs-story-name="fooPreviewStory"></mdjs-preview>',
|
'<mdjs-preview mdjs-story-name="fooPreviewStory">',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'<pre><code class="language-js">export const fooPreviewStory = () => {}',
|
||||||
|
'</code></pre>',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'</mdjs-preview>',
|
||||||
'<mdjs-story mdjs-story-name="HtmlStory0"></mdjs-story>',
|
'<mdjs-story mdjs-story-name="HtmlStory0"></mdjs-story>',
|
||||||
'<mdjs-preview mdjs-story-name="HtmlStory1"></mdjs-preview>',
|
'<mdjs-preview mdjs-story-name="HtmlStory1">',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'<pre><code class="language-html"><demo-el></demo-el>',
|
||||||
|
'</code></pre>',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'</mdjs-preview>',
|
||||||
'',
|
'',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
|
|||||||
1
packages/mdjs-core/types/code.d.ts
vendored
1
packages/mdjs-core/types/code.d.ts
vendored
@@ -25,6 +25,7 @@ export interface ParseResult {
|
|||||||
data: {
|
data: {
|
||||||
stories: Story[];
|
stories: Story[];
|
||||||
jsCode: string;
|
jsCode: string;
|
||||||
|
setupJsCode: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,88 @@
|
|||||||
# @mdjs/mdjs-preview
|
# @mdjs/mdjs-preview
|
||||||
|
|
||||||
|
## 0.5.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- e1e96ac: **BREAKING CHANGE** Update to [lit](https://lit.dev/) 2
|
||||||
|
|
||||||
|
If your main lit-html version is 1.x be sure to import html for your story rendering from `@mdjs/mdjs-preview`.
|
||||||
|
|
||||||
|
````md
|
||||||
|
```js script
|
||||||
|
import { html } from '@mdjs/mdjs-preview';
|
||||||
|
```
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const foo = () =>
|
||||||
|
html`
|
||||||
|
<demo-element></demo-element>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
- 814b5d2: **BREAKING CHANGE** Render stories to light dom
|
||||||
|
|
||||||
|
```js
|
||||||
|
export const story = html`
|
||||||
|
<p>my story</p>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- before -->
|
||||||
|
<mdjs-preview>
|
||||||
|
#shadow-root (open)
|
||||||
|
<div id="wrapper">
|
||||||
|
<div>
|
||||||
|
<p>my story</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- more internal dom -->
|
||||||
|
|
||||||
|
<code><!-- ... --></code>
|
||||||
|
</mdjs-preview>
|
||||||
|
|
||||||
|
<!-- after -->
|
||||||
|
<mdjs-preview>
|
||||||
|
#shadow-root (open)
|
||||||
|
<div id="wrapper">
|
||||||
|
<!-- more internal dom -->
|
||||||
|
|
||||||
|
<code><!-- ... --></code>
|
||||||
|
<div slot="story">
|
||||||
|
<p>my story</p>
|
||||||
|
</div>
|
||||||
|
</mdjs-preview>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 0.4.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 72f631a: Improve customizations by hiding empty themes, platforms and adding parts to be styled.
|
||||||
|
- 74dd8d1: Autoheight will not grow bigger than the current size height
|
||||||
|
- 72f631a: Add a copy code button
|
||||||
|
|
||||||
|
## 0.4.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 0f6709a: Make sure initial settings are taken from the element if nothing is yet stored
|
||||||
|
|
||||||
|
## 0.4.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- edb1abf: Reworking completely by
|
||||||
|
|
||||||
|
- slotting in the highlighted code
|
||||||
|
- open story in dedicated window
|
||||||
|
- enabling an simulation mode that can render the story in an iframe
|
||||||
|
- share settings between all simulators
|
||||||
|
- option to remember simulator settings
|
||||||
|
- force side effect import via `/define`
|
||||||
|
|
||||||
## 0.3.2
|
## 0.3.2
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1 +1,62 @@
|
|||||||
export { MdJsPreview } from './src/MdJsPreview.js';
|
export { MdJsPreview } from './src/MdJsPreview.js';
|
||||||
|
|
||||||
|
// reexport used lit to ensure users can sync html & rendering
|
||||||
|
export {
|
||||||
|
html,
|
||||||
|
CSSResult,
|
||||||
|
adoptStyles,
|
||||||
|
css,
|
||||||
|
getCompatibleStyle,
|
||||||
|
supportsAdoptingStyleSheets,
|
||||||
|
unsafeCSS,
|
||||||
|
UpdatingElement,
|
||||||
|
notEqual,
|
||||||
|
ReactiveElement,
|
||||||
|
svg,
|
||||||
|
noChange,
|
||||||
|
nothing,
|
||||||
|
render,
|
||||||
|
LitElement,
|
||||||
|
defaultConverter,
|
||||||
|
} from 'lit';
|
||||||
|
|
||||||
|
export {
|
||||||
|
customElement,
|
||||||
|
property,
|
||||||
|
state,
|
||||||
|
eventOptions,
|
||||||
|
query,
|
||||||
|
queryAll,
|
||||||
|
queryAsync,
|
||||||
|
queryAssignedNodes,
|
||||||
|
} from 'lit/decorators.js';
|
||||||
|
|
||||||
|
export { directive, Directive } from 'lit/directive.js';
|
||||||
|
|
||||||
|
export { AsyncDirective } from 'lit/async-directive.js';
|
||||||
|
|
||||||
|
export {
|
||||||
|
isPrimitive,
|
||||||
|
TemplateResultType,
|
||||||
|
isTemplateResult,
|
||||||
|
isDirectiveResult,
|
||||||
|
getDirectiveClass,
|
||||||
|
isSingleExpression,
|
||||||
|
insertPart,
|
||||||
|
setChildPartValue,
|
||||||
|
setCommittedValue,
|
||||||
|
getCommittedValue,
|
||||||
|
removePart,
|
||||||
|
clearPart,
|
||||||
|
} from 'lit/directive-helpers.js';
|
||||||
|
|
||||||
|
export { asyncAppend } from 'lit/directives/async-append.js';
|
||||||
|
export { asyncReplace } from 'lit/directives/async-replace.js';
|
||||||
|
export { cache } from 'lit/directives/cache.js';
|
||||||
|
export { classMap } from 'lit/directives/class-map.js';
|
||||||
|
export { guard } from 'lit/directives/guard.js';
|
||||||
|
export { ifDefined } from 'lit/directives/if-defined.js';
|
||||||
|
export { repeat } from 'lit/directives/repeat.js';
|
||||||
|
export { styleMap } from 'lit/directives/style-map.js';
|
||||||
|
export { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
||||||
|
export { until } from 'lit/directives/until.js';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mdjs/mdjs-preview",
|
"name": "@mdjs/mdjs-preview",
|
||||||
"version": "0.3.2",
|
"version": "0.5.0",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
@@ -17,12 +17,11 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./index.js",
|
".": "./index.js",
|
||||||
"./mdjs-preview.js": "./mdjs-preview.js"
|
"./define": "./src/define/define.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"debug": "cd ../../ && npm run debug -- --group mdjs-preview",
|
"debug": "cd ../../ && npm run debug -- --group mdjs-preview",
|
||||||
"test": "npm run test:web",
|
"test": "npm run test:web",
|
||||||
"test:watch": "onchange 'src/**/*.{js,cjs}' 'test-node/**/*.js' -- npm run test:node",
|
|
||||||
"test:web": "cd ../../ && npm run test:web -- --group mdjs-preview"
|
"test:web": "cd ../../ && npm run test:web -- --group mdjs-preview"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
@@ -32,8 +31,8 @@
|
|||||||
"src"
|
"src"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lit-element": "^2.4.0",
|
"@lion/accordion": "^0.4.2",
|
||||||
"lit-html": "^1.3.0"
|
"lit": "^2.0.0-rc.2"
|
||||||
},
|
},
|
||||||
"types": "dist-types/index.d.ts"
|
"types": "dist-types/index.d.ts"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
import { LitElement, html, css } from 'lit-element';
|
import { LitElement, html, css, nothing, render } from 'lit';
|
||||||
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
|
import '@lion/accordion/define';
|
||||||
|
|
||||||
|
import {
|
||||||
|
subscribe,
|
||||||
|
unSubscribe,
|
||||||
|
saveToSharedStates,
|
||||||
|
applySharedStates,
|
||||||
|
} from './mdjsViewerSharedStates.js';
|
||||||
|
import { addResizeHandler } from './resizeHandler.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {object} StoryOptions
|
* @typedef {object} StoryOptions
|
||||||
* @property {ShadowRoot | null} StoryOptions.shadowRoot
|
* @property {HTMLElement | null} StoryOptions.shadowRoot
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @typedef {(options?: StoryOptions) => ReturnType<LitElement['render']>} LitHtmlStoryFn */
|
/** @typedef {(options?: StoryOptions) => ReturnType<LitElement['render']>} LitHtmlStoryFn */
|
||||||
@@ -20,160 +28,815 @@ export class MdJsPreview extends LitElement {
|
|||||||
story: {
|
story: {
|
||||||
attribute: false,
|
attribute: false,
|
||||||
},
|
},
|
||||||
code: {
|
key: {
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
codeHasHtml: {
|
deviceMode: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
},
|
attribute: 'device-mode',
|
||||||
showCode: {
|
|
||||||
type: Boolean,
|
|
||||||
attribute: 'show-code',
|
|
||||||
reflect: true,
|
reflect: true,
|
||||||
},
|
},
|
||||||
|
sameSettings: { type: Boolean },
|
||||||
|
contentHeight: { type: Number },
|
||||||
|
simulatorUrl: { type: String },
|
||||||
|
// page settings
|
||||||
|
platform: { type: String },
|
||||||
|
platforms: { type: Array },
|
||||||
|
size: { type: String },
|
||||||
|
sizes: { type: Array },
|
||||||
|
theme: { type: String, reflect: true },
|
||||||
|
themes: { type: Array },
|
||||||
|
language: { type: String },
|
||||||
|
languages: { type: Array },
|
||||||
|
edgeDistance: { type: Boolean },
|
||||||
|
autoHeight: { type: Boolean },
|
||||||
|
rememberSettings: { type: Boolean },
|
||||||
|
__copyButtonText: { type: String },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleShowCode() {
|
|
||||||
this.showCode = !this.showCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.code = '';
|
|
||||||
/** @type {LitHtmlStoryFn} */
|
/** @type {LitHtmlStoryFn} */
|
||||||
this.story = () => html` <p>Loading...</p> `;
|
this.story = () => html` <p>Loading...</p> `;
|
||||||
this.codeHasHtml = false;
|
this.key = '';
|
||||||
|
this.contentHeight = 0;
|
||||||
|
this.simulatorUrl = '';
|
||||||
|
this.__supportsClipboard = 'clipboard' in navigator;
|
||||||
|
this.__copyButtonText = 'Copy Code';
|
||||||
|
|
||||||
|
this.theme = 'light';
|
||||||
|
/** @type {{ key: string, name: string }[]} */
|
||||||
|
this.themes = [
|
||||||
|
// { key: 'light', name: 'Light' },
|
||||||
|
// { key: 'dark', name: 'Dark' },
|
||||||
|
];
|
||||||
|
|
||||||
|
this.language = 'en-US';
|
||||||
|
this.languages = [
|
||||||
|
{ key: 'en', name: 'English' },
|
||||||
|
{ key: 'en-US', name: 'English (United States)' },
|
||||||
|
{ key: 'en-GB', name: 'English (United Kingdom)' },
|
||||||
|
{ key: 'de', name: 'German' },
|
||||||
|
{ key: 'es', name: 'Spanish' },
|
||||||
|
{ key: 'fi', name: 'Finnish' },
|
||||||
|
{ key: 'fr', name: 'French' },
|
||||||
|
{ key: 'it', name: 'Italian' },
|
||||||
|
{ key: 'nl', name: 'Dutch' },
|
||||||
|
{ key: 'pl', name: 'Polish' },
|
||||||
|
{ key: 'pt', name: 'Portuguese' },
|
||||||
|
{ key: 'ro', name: 'Romanian' },
|
||||||
|
{ key: 'sv', name: 'Swedish' },
|
||||||
|
];
|
||||||
|
|
||||||
|
this.platform = 'web';
|
||||||
|
|
||||||
|
/** @type {{ key: string, name: string }[]} */
|
||||||
|
this.platforms = [
|
||||||
|
// { key: 'web', name: 'Web' },
|
||||||
|
// { key: 'web-windows', name: 'Windows' },
|
||||||
|
// { key: 'web-mac', name: 'Mac' },
|
||||||
|
// { key: 'android', name: 'Android' },
|
||||||
|
// { key: 'ios', name: 'iOS' },
|
||||||
|
];
|
||||||
|
|
||||||
|
this.size = 'webSmall';
|
||||||
|
this.sizes = [
|
||||||
|
{
|
||||||
|
key: 'webSmall',
|
||||||
|
name: 'Small',
|
||||||
|
platform: 'web',
|
||||||
|
width: 360,
|
||||||
|
height: 640,
|
||||||
|
dpr: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'webMedium',
|
||||||
|
name: 'Medium',
|
||||||
|
platform: 'web',
|
||||||
|
width: 640,
|
||||||
|
height: 640,
|
||||||
|
dpr: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'webLarge',
|
||||||
|
name: 'Large',
|
||||||
|
platform: 'web',
|
||||||
|
width: 1024,
|
||||||
|
height: 640,
|
||||||
|
dpr: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'pixel2',
|
||||||
|
name: 'Pixel 2',
|
||||||
|
platform: 'android',
|
||||||
|
width: 411,
|
||||||
|
height: 731,
|
||||||
|
dpr: 2.6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'galaxyS5',
|
||||||
|
name: 'Galaxy S5',
|
||||||
|
platform: 'android',
|
||||||
|
width: 360,
|
||||||
|
height: 640,
|
||||||
|
dpr: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'iphoneX',
|
||||||
|
name: 'iPhone X',
|
||||||
|
platform: 'ios',
|
||||||
|
width: 375,
|
||||||
|
height: 812,
|
||||||
|
dpr: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'iPad',
|
||||||
|
name: 'iPad',
|
||||||
|
platform: 'ios',
|
||||||
|
width: 768,
|
||||||
|
height: 1024,
|
||||||
|
dpr: 2,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
this.deviceMode = false;
|
||||||
|
this.autoHeight = true;
|
||||||
|
this.edgeDistance = true;
|
||||||
|
this.sameSettings = true;
|
||||||
|
this.rememberSettings = false;
|
||||||
|
|
||||||
|
this.__firstRun = true;
|
||||||
|
this.__syncUp = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
if (!this.lightDomRenderTarget) {
|
||||||
|
this.lightDomRenderTarget = document.createElement('div');
|
||||||
|
this.lightDomRenderTarget.setAttribute('slot', 'story');
|
||||||
|
this.appendChild(this.lightDomRenderTarget);
|
||||||
|
}
|
||||||
|
if (this.sameSettings) {
|
||||||
|
applySharedStates(this);
|
||||||
|
}
|
||||||
|
addResizeHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
get baseUrl() {
|
||||||
|
return document.location.origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
get deviceHeight() {
|
||||||
|
const maxHeight = this.sizeData?.height || 50;
|
||||||
|
if (this.autoHeight) {
|
||||||
|
return Math.min(this.contentHeight, maxHeight);
|
||||||
|
}
|
||||||
|
return maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} platform
|
||||||
|
*/
|
||||||
|
getSizesFor(platform) {
|
||||||
|
return this.sizes.filter(el => el.platform === platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
get sizeData() {
|
||||||
|
return (
|
||||||
|
this.sizes.find(el => el.key === this.size) || { width: 50, height: 50, name: 'default' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubscribe = () => {
|
||||||
|
this.__syncUp = false;
|
||||||
|
applySharedStates(this);
|
||||||
|
this.__syncUp = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('lit-element').PropertyValues} changeProps
|
||||||
|
*/
|
||||||
|
update(changeProps) {
|
||||||
|
super.update(changeProps);
|
||||||
|
if (this.sameSettings && this.__syncUp) {
|
||||||
|
saveToSharedStates(this, this.onSubscribe);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changeProps.has('sameSettings')) {
|
||||||
|
if (this.sameSettings) {
|
||||||
|
subscribe(this.onSubscribe);
|
||||||
|
} else {
|
||||||
|
unSubscribe(this.onSubscribe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lightDomRenderTarget && changeProps.has('story')) {
|
||||||
|
render(this.story({ shadowRoot: this }), this.lightDomRenderTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
if (this.sameSettings) {
|
||||||
|
unSubscribe(this.onSubscribe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this.__syncUp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
get iframeUrl() {
|
||||||
|
const mdjsSetupScript = /** @type {HTMLScriptElement} */ (document.querySelector(
|
||||||
|
'script[type=module][mdjs-setup]',
|
||||||
|
));
|
||||||
|
if (!mdjsSetupScript) {
|
||||||
|
throw new Error('Could not find a <script type="module" src="..." mdjs-setup></script>');
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.set('story-file', mdjsSetupScript.src);
|
||||||
|
params.set('story-key', this.key);
|
||||||
|
params.set('theme', this.theme);
|
||||||
|
params.set('platform', this.platform);
|
||||||
|
params.set('language', this.language);
|
||||||
|
params.set('edge-distance', this.edgeDistance.toString());
|
||||||
|
|
||||||
|
const links = /** @type {HTMLLinkElement[]} */ ([
|
||||||
|
...document.querySelectorAll('link[mdjs-use]'),
|
||||||
|
]);
|
||||||
|
for (const link of links) {
|
||||||
|
if (link.href) {
|
||||||
|
params.append('stylesheets', link.href);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${this.simulatorUrl}#?${params.toString()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} platform
|
||||||
|
*/
|
||||||
|
changePlatform(platform) {
|
||||||
|
this.platform = platform;
|
||||||
|
const sizes = this.getSizesFor(this.platform);
|
||||||
|
this.size = sizes[0].key;
|
||||||
|
}
|
||||||
|
|
||||||
|
async onCopy() {
|
||||||
|
if (this.textContent) {
|
||||||
|
await navigator.clipboard.writeText(this.textContent.trim());
|
||||||
|
this.__copyButtonText = 'Copied ✅';
|
||||||
|
setTimeout(() => {
|
||||||
|
this.__copyButtonText = 'Copy code';
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPlatforms() {
|
||||||
|
if (this.platforms.length) {
|
||||||
|
return html`
|
||||||
|
<h4>Platform</h4>
|
||||||
|
<div
|
||||||
|
class="segmented-control"
|
||||||
|
@change=${
|
||||||
|
/** @param {Event} ev */ ev => {
|
||||||
|
if (ev.target) {
|
||||||
|
this.changePlatform(/** @type {HTMLInputElement} */ (ev.target).value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
${this.platforms.map(
|
||||||
|
platform => html`
|
||||||
|
<label class="${this.platform === platform.key ? 'selected' : ''}">
|
||||||
|
<span>${platform.name}</span>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="platform"
|
||||||
|
value="${platform.key}"
|
||||||
|
?checked=${this.platform === platform.key}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
`,
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPlatform() {
|
||||||
|
if (this.platforms.length) {
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<h3>Platform</h3>
|
||||||
|
${this.renderPlatforms()}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSizes() {
|
||||||
|
if (this.sizes.length) {
|
||||||
|
return html`
|
||||||
|
<h4>Size</h4>
|
||||||
|
<div
|
||||||
|
class="segmented-control"
|
||||||
|
@change=${
|
||||||
|
/** @param {Event} ev */ ev => {
|
||||||
|
if (ev.target) {
|
||||||
|
this.size = /** @type {HTMLInputElement} */ (ev.target).value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
${this.getSizesFor(this.platform).map(
|
||||||
|
size => html`
|
||||||
|
<label class="${this.size === size.key ? 'selected' : ''}">
|
||||||
|
<span>${size.name}</span>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="size"
|
||||||
|
value="${size.key}"
|
||||||
|
.checked=${this.size === size.key}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
`,
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderViewport() {
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<h3>Viewport</h3>
|
||||||
|
${this.renderSizes()} ${this.renderAutoHeight()}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderThemes() {
|
||||||
|
if (this.themes.length) {
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
class="segmented-control"
|
||||||
|
@change=${
|
||||||
|
/** @param {Event} ev */ ev => {
|
||||||
|
if (ev.target) {
|
||||||
|
this.theme = /** @type {HTMLInputElement} */ (ev.target).value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
${this.themes.map(
|
||||||
|
theme => html`
|
||||||
|
<label class="${this.theme === theme.key ? 'selected' : ''}">
|
||||||
|
<span>${theme.name}</span>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="theme"
|
||||||
|
value="${theme.key}"
|
||||||
|
?checked=${this.theme === theme.key}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
`,
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderVisual() {
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<h3>Visual</h3>
|
||||||
|
${this.renderThemes()} ${this.renderEdgeDistance()}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLanguages() {
|
||||||
|
if (this.languages.length) {
|
||||||
|
return html`
|
||||||
|
<label>
|
||||||
|
Language
|
||||||
|
<select
|
||||||
|
@change=${
|
||||||
|
/** @param {Event} ev */ ev => {
|
||||||
|
if (ev.target) {
|
||||||
|
this.language = /** @type {HTMLInputElement} */ (ev.target).value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
${this.languages.map(
|
||||||
|
language => html`
|
||||||
|
<option value="${language.key}" ?selected=${this.language === language.key}>
|
||||||
|
${language.name}
|
||||||
|
</option>
|
||||||
|
`,
|
||||||
|
)}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLocalization() {
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<h3>Localization</h3>
|
||||||
|
${this.renderLanguages()}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderEdgeDistance() {
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<label class="${this.edgeDistance ? 'switch selected' : 'switch'}">
|
||||||
|
Apply distance to edge
|
||||||
|
<span part="switch-button"></span>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
?checked=${this.edgeDistance}
|
||||||
|
@change=${
|
||||||
|
/** @param {Event} ev */ ev => {
|
||||||
|
if (ev.target) {
|
||||||
|
this.edgeDistance = /** @type {HTMLInputElement} */ (ev.target).checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAutoHeight() {
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<label class="${this.autoHeight ? 'switch selected' : 'switch'}">
|
||||||
|
Fit height to content
|
||||||
|
<span part="switch-button"></span>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
?checked=${this.autoHeight}
|
||||||
|
@change=${
|
||||||
|
/** @param {Event} ev */ ev => {
|
||||||
|
if (ev.target) {
|
||||||
|
this.autoHeight = /** @type {HTMLInputElement} */ (ev.target).checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSameSettings() {
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<label class="${this.sameSettings ? 'switch selected' : 'switch'}">
|
||||||
|
Same settings for all simulations
|
||||||
|
<span part="switch-button"></span>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
?checked=${this.sameSettings}
|
||||||
|
@change=${
|
||||||
|
/** @param {Event} ev */ ev => {
|
||||||
|
if (ev.target) {
|
||||||
|
this.sameSettings = /** @type {HTMLInputElement} */ (ev.target).checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRememberSettings() {
|
||||||
|
if (!this.sameSettings) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<label class="${this.rememberSettings ? 'switch selected' : 'switch'}">
|
||||||
|
Remember settings
|
||||||
|
<span part="switch-button"></span>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
?checked=${this.rememberSettings}
|
||||||
|
@change=${
|
||||||
|
/** @param {Event} ev */ ev => {
|
||||||
|
if (ev.target) {
|
||||||
|
this.rememberSettings = /** @type {HTMLInputElement} */ (ev.target).checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSyncSettings() {
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<h3>Global</h3>
|
||||||
|
${this.renderSameSettings()} ${this.renderRememberSettings()}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div id="wrapper">
|
<div id="wrapper">
|
||||||
<div>${this.story({ shadowRoot: this.shadowRoot })}</div>
|
<slot name="story"></slot>
|
||||||
<button id="showCodeButton" @click=${this.toggleShowCode}>show code</button>
|
${this.deviceMode === true
|
||||||
|
? html`
|
||||||
|
<iframe
|
||||||
|
part="iframe"
|
||||||
|
csp=${`script-src ${document.location.origin} 'unsafe-inline'; connect-src ws://${document.location.host}/`}
|
||||||
|
.src=${this.iframeUrl}
|
||||||
|
style=${`width: ${this.sizeData.width}px; height: ${this.deviceHeight}px;`}
|
||||||
|
></iframe>
|
||||||
|
<p part="frame-description" style=${`width: ${this.sizeData.width + 4}px;`}>
|
||||||
|
${this.sizeData.name} - ${this.deviceHeight}x${this.sizeData.width}
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
</div>
|
</div>
|
||||||
${this.codeHasHtml ? unsafeHTML(this.code) : html`<pre><code>${this.code}</code></pre>`}
|
<lion-accordion class="options">
|
||||||
|
${this.deviceMode
|
||||||
|
? html`
|
||||||
|
<h3 slot="invoker">
|
||||||
|
<button>Settings</button>
|
||||||
|
</h3>
|
||||||
|
<div slot="content">
|
||||||
|
<div class="settings-wrapper">
|
||||||
|
${this.renderPlatform()} ${this.renderViewport()} ${this.renderVisual()}
|
||||||
|
${this.renderLocalization()} ${this.renderSyncSettings()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ''}
|
||||||
|
<h3 slot="invoker">
|
||||||
|
<button>Code</button>
|
||||||
|
</h3>
|
||||||
|
<div slot="content">
|
||||||
|
<slot id="code-slot"></slot>
|
||||||
|
<button part="copy-button" @click="${this.onCopy}" ?hidden="${!this.__supportsClipboard}">
|
||||||
|
${this.__copyButtonText}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</lion-accordion>
|
||||||
|
${this.simulatorUrl
|
||||||
|
? html`
|
||||||
|
<div class="controls">
|
||||||
|
<a href=${this.iframeUrl} target="_blank">Open simulation in new window</a>
|
||||||
|
<button
|
||||||
|
@click=${() => (this.deviceMode = !this.deviceMode)}
|
||||||
|
class="simulation-toggle"
|
||||||
|
>
|
||||||
|
${this.deviceMode ? html`Disable` : html`Enable`} device simulation
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ''}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
border: 1px solid #ccc;
|
|
||||||
display: block;
|
display: block;
|
||||||
box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#showCodeButton {
|
:host([device-mode]) slot[name='story'] {
|
||||||
position: absolute;
|
display: none;
|
||||||
right: 5px;
|
}
|
||||||
bottom: 5px;
|
|
||||||
|
iframe {
|
||||||
|
border: 2px solid #4caf50;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
[part='copy-button'] {
|
||||||
|
border: 1px solid var(--primary-color, #3f51b5);
|
||||||
|
border-radius: 9px;
|
||||||
|
padding: 7px;
|
||||||
|
background: none;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--primary-color, #3f51b5);
|
||||||
|
text-align: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 20px;
|
line-height: 12px;
|
||||||
color: #24292e;
|
float: right;
|
||||||
background-color: #eff3f6;
|
margin-top: -10px;
|
||||||
background-image: linear-gradient(-180deg, #fafbfc, #eff3f6 90%);
|
}
|
||||||
|
|
||||||
|
[part='copy-button']:hover {
|
||||||
|
background-color: var(--primary-color, #3f51b5);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch:focus-within [part='switch-button'] {
|
||||||
|
box-shadow: 0 0 0 1px hsl(0deg 0% 100% / 40%), 0 0 0 4px rgb(31 117 203 / 48%);
|
||||||
|
}
|
||||||
|
|
||||||
|
[part='switch-button'] {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 3px 12px;
|
width: 44px;
|
||||||
white-space: nowrap;
|
background: #808080;
|
||||||
vertical-align: middle;
|
height: 25px;
|
||||||
cursor: pointer;
|
border-radius: 15px;
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
background-repeat: repeat-x;
|
|
||||||
background-position: -1px -1px;
|
|
||||||
background-size: 110% 110%;
|
|
||||||
border: 1px solid rgba(27, 31, 35, 0.2);
|
|
||||||
border-radius: 0.25em;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
-moz-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#showCodeButton:hover {
|
|
||||||
background-color: #e6ebf1;
|
|
||||||
background-image: linear-gradient(-180deg, #f0f3f6, #e6ebf1 90%);
|
|
||||||
background-position: -0.5em;
|
|
||||||
border-color: rgba(27, 31, 35, 0.35);
|
|
||||||
text-decoration: none;
|
|
||||||
background-repeat: repeat-x;
|
|
||||||
}
|
|
||||||
|
|
||||||
#wrapper {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
[part='switch-button']::after {
|
||||||
|
content: ' ';
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgb(255, 255, 255);
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch.selected [part='switch-button'] {
|
||||||
|
background: var(--primary-color, #008000);
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch.selected [part='switch-button']::after {
|
||||||
|
left: auto;
|
||||||
|
right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[part='frame-description'] {
|
||||||
|
margin: -5px 0 10px 0;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-gap: 20px 40px;
|
||||||
|
max-width: 650px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.settings-wrapper {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-wrapper h3 {
|
||||||
|
margin: 10px 0;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
display: block;
|
||||||
|
padding: 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls a {
|
||||||
|
color: var(--primary-color, #3f51b5);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 37px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.simulation-toggle {
|
||||||
|
border: 1px solid var(--primary-color, #3f51b5);
|
||||||
|
border-radius: 9px;
|
||||||
|
padding: 10px;
|
||||||
|
background: none;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--primary-color, #3f51b5);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.simulation-toggle:hover {
|
||||||
|
background-color: var(--primary-color, #3f51b5);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3[slot='invoker'] button {
|
||||||
|
font-size: 16px;
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
padding: 10px;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #bbb;
|
||||||
|
width: 100%;
|
||||||
|
background: none;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3[slot='invoker'] button::after {
|
||||||
|
content: '>';
|
||||||
|
right: 20px;
|
||||||
|
top: 10px;
|
||||||
|
position: absolute;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
h3[slot='invoker'][expanded='true'] button::after {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
h3[slot='invoker'][expanded='true'] button {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[slot='content'] {
|
||||||
|
border-bottom: 1px solid #bbb;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host > pre {
|
h3[slot='invoker']:first-child button {
|
||||||
display: none;
|
border-top: 1px solid #bbb;
|
||||||
margin: 0;
|
|
||||||
padding: 16px;
|
|
||||||
overflow: auto;
|
|
||||||
font-size: 85%;
|
|
||||||
line-height: 1.45;
|
|
||||||
background-color: #f6f8fa;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([show-code]) > pre {
|
h4 {
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control {
|
||||||
|
border: 1px solid var(--primary-color, #3f51b5);
|
||||||
|
border-radius: 18px;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control span {
|
||||||
|
padding: 5px 10px;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 18px;
|
||||||
|
margin: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control label:first-child span {
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control label:last-child span {
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control label.selected span {
|
||||||
|
background: var(--primary-color, #3f51b5);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control label:focus-within span {
|
||||||
|
box-shadow: 0 0 0 1px hsl(0deg 0% 100% / 40%), 0 0 0 4px rgb(31 117 203 / 48%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.segmented-control input,
|
||||||
|
.switch input {
|
||||||
|
clip: rect(0 0 0 0);
|
||||||
|
clip-path: inset(50%);
|
||||||
|
height: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
padding: 5px;
|
||||||
|
border: 1px solid #333;
|
||||||
code[class*='language-'],
|
|
||||||
pre[class*='language-'] {
|
|
||||||
color: #393a34;
|
|
||||||
font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
|
||||||
direction: ltr;
|
|
||||||
text-align: left;
|
|
||||||
white-space: pre;
|
|
||||||
word-spacing: normal;
|
|
||||||
word-break: normal;
|
|
||||||
tab-size: 4;
|
|
||||||
hyphens: none;
|
|
||||||
overflow: auto;
|
|
||||||
font-size: 85%;
|
|
||||||
line-height: 1.45;
|
|
||||||
background-color: #f6f8fa;
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.token.function,
|
|
||||||
.token.class-name {
|
|
||||||
color: #6f42c1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.tag,
|
|
||||||
.token.selector,
|
|
||||||
.language-autohotkey .token.keyword {
|
|
||||||
color: #22863a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.entity,
|
|
||||||
.token.url,
|
|
||||||
.token.symbol,
|
|
||||||
.token.number,
|
|
||||||
.token.boolean,
|
|
||||||
.token.variable,
|
|
||||||
.token.constant,
|
|
||||||
.token.property,
|
|
||||||
.token.inserted,
|
|
||||||
.token.punctuation,
|
|
||||||
.token.operator {
|
|
||||||
color: #005cc5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.regex {
|
|
||||||
color: #032f62;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.atrule,
|
|
||||||
.token.keyword,
|
|
||||||
.token.attr-name,
|
|
||||||
.language-autohotkey .token.selector {
|
|
||||||
color: #d73a49;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
import { MdJsPreview } from './src/MdJsPreview.js';
|
import { MdJsPreview } from '../MdJsPreview.js';
|
||||||
|
|
||||||
customElements.define('mdjs-preview', MdJsPreview);
|
customElements.define('mdjs-preview', MdJsPreview);
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user