Compare commits

...

20 Commits

Author SHA1 Message Date
Thomas Allmer
0166dc6f04 feat(web-menu): initial release 2021-11-07 13:53:04 +01:00
github-actions[bot]
0197bee621 Version Packages 2021-10-15 19:25:11 +02:00
Thomas Allmer
5c6b9c91eb feat(mdjs-preview): Move platform and sizes settings above preview 2021-10-15 12:33:30 +02:00
Thomas Allmer
6221e5f9ea feat: mdjs support for story-code blocks 2021-10-15 12:33:30 +02:00
Jorge del Casar
06741ed729 chore: update playwright 2021-10-11 19:23:33 +02:00
Thomas Allmer
23c164c822 chore: reduce test output noise 2021-10-03 22:06:22 +02:00
github-actions[bot]
c2a76c3f53 Version Packages 2021-10-03 17:15:38 +02:00
Thomas Allmer
70bb7a128e feat: update all packages to use new plugins-manager api 2021-10-03 17:10:18 +02:00
Thomas Allmer
3c342473d7 feat(plugin-manager): new type safe API
Co-authored-by: Benny Powers <web@bennypowers.com>
2021-10-03 17:10:18 +02:00
Thomas Allmer
9e0579ab19 chore: version linting considering valid semver 2021-09-13 15:22:52 +02:00
Thomas Allmer
de202da0a5 chore: reenable all tests 2021-09-13 15:22:52 +02:00
github-actions[bot]
509a8d9115 Version Packages 2021-09-13 13:33:26 +02:00
Mathieu Puech
42418f2c00 fix: disable service worker for local development 2021-09-13 13:29:05 +02:00
Benny Powers
cadd8588b0 fix(blog): conditionally apply blog overview styles 2021-09-13 12:36:51 +02:00
Benny Powers
aabe011427 Update 30-articles.njk 2021-09-13 12:36:51 +02:00
qa46hx
e1089c5701 fix(blog): add title to blog page 2021-09-13 12:36:38 +02:00
Benny Powers
9f10386eb2 fix: hide 404 page from sitemap.xml 2021-08-10 23:57:52 +02:00
qa46hx
0987a41620 fix(mdjs-viewer): fix styling mdjs-viewer 2021-08-10 23:55:09 +02:00
Thomas Allmer
7301a0f354 feat(cli): enable conditional eleventy config 2021-08-01 16:49:20 +02:00
Thomas Allmer
5ac6aa6693 fix(cli): set the encoding of the simulator to utf8 2021-07-27 21:03:51 +02:00
239 changed files with 6526 additions and 1147 deletions

1
.gitignore vendored
View File

@@ -40,3 +40,4 @@ _merged_assets
_merged_includes
__output
__output-dev
docs_backup

View File

@@ -1,4 +1,6 @@
---
layout: layout-404
permalink: 404.html
menu:
exclude: true
---

View File

@@ -1,8 +1,8 @@
:not(rocket-navigation):not(:defined) {
:not(web-menu):not(:defined) {
opacity: 0;
}
rocket-navigation,
web-menu,
header {
font-family: 'Montserrat', sans-serif;
}

View File

@@ -19,6 +19,9 @@ html {
--primary-color: rgb(44, 62, 80);
--primary-lines-color: #ccc;
--primary-text-color: #2c3e50;
--primary-text-inverse-color: #eee;
--switch-unselected-color: #808080;
--switch-selected-color: #42b983;
}
@media (prefers-color-scheme: dark) {
@@ -45,6 +48,9 @@ html {
--rocket-search-highlight-color: #41ffb0;
--rocket-search-hover-background-color: #6b717a;
--rocket-search-fill-color: #fff;
--primary-text-inverse-color: #2c3e50;
--switch-unselected-color: #808080;
--switch-selected-color: #42b983;
/* Markdown */
--markdown-octicon-link: var(--primary-text-color);

View File

@@ -0,0 +1,3 @@
module.exports = {
layout: 'layout-blog-details',
};

View File

@@ -110,7 +110,9 @@ export default ({
## Advanced
Sometimes you need even more control over the build process. In these cases you can take full control over the rollup config.
Sometimes you need even more control over specific settings.
### Rollup
For example if you wanna add an `acron` plugin to rollup
@@ -127,3 +129,38 @@ export default ({
});
```
<!-- prettier-ignore-end -->
### Eleventy
For example to add custom filter you can access the eleventy config directly
<!-- prettier-ignore-start -->
```js
/** @type {import('rocket/cli').RocketCliConfig} */
export default ({
eleventy: eleventyConfig => {
eleventyConfig.addFilter('value', value => `prefix${value}`);
},
});
```
<!-- prettier-ignore-end -->
You even have access to the full rocketConfig if you for example want to create filters that behave differently during start/build.
<!-- prettier-ignore-start -->
```js
/** @type {import('rocket/cli').RocketCliConfig} */
export default ({
eleventy: (config, rocketConfig) => {
config.addFilter('conditional-resolve', value => {
if (rocketConfig.command === 'build') {
return `build:${value}`;
}
if (rocketConfig.command === 'start') {
return `start:${value}`;
}
});
},
});
```
<!-- prettier-ignore-end -->

View File

@@ -123,6 +123,68 @@ export const header = () => {
};
```
```js story-code
// not defined for android
```
```js story-code
// not defined for ios
```
#### Story Code
If your preview is followed by a code blocks marked as `story-code` then those will be shown when switching between multiple platforms
````md
```js preview-story
// will be visible when platform web is selected
export const JsPreviewStory = () => html` <demo-wc-card>JS Preview Story</demo-wc-card> `;
```
```xml story-code
<!-- will be visible when platform android is selected -->
<Button
android:id="@+id/demoWcCard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android Code"
style="@style/Widget.FooComponents.Demo.Wc.Card"
/>
```
```swift story-code
// will be visible when platform ios is selected
import DemoWc.Card
let card = DemoWcButton()
```
````
See it in action by opening up the code block and switching platforms
```js preview-story
// will be visible when platform web is selected
export const JsPreviewStory = () => html` <demo-wc-card>JS Preview Story</demo-wc-card> `;
```
```xml story-code
<!-- will be visible when platform android is selected -->
<Button
android:id="@+id/demoWcCard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android Code"
style="@style/Widget.FooComponents.Demo.Wc.Card"
/>
```
```swift story-code
// will be visible when platform ios is selected
import DemoWc.Card
let card = DemoWcButton()
```
## Supported Systems
### Storybook

View File

@@ -40,6 +40,68 @@ will result in
export const foo = () => html` <demo-element></demo-element> `;
```
```js story-code
// not defined for android
```
```js story-code
// not defined for ios
```
#### Story Code
If your preview is followed by a code blocks marked as `story-code` then those will be shown when switching between multiple platforms
````md
```js preview-story
// will be visible when platform web is selected
export const JsPreviewStory = () => html` <demo-element></demo-element> `;
```
```xml story-code
<!-- will be visible when platform android is selected -->
<Button
android:id="@+id/demoElement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android Code"
style="@style/Widget.Demo.Element"
/>
```
```swift story-code
// will be visible when platform ios is selected
import Demo.Element
let card = DemoElement()
```
````
See it in action by opening up the code block and switching platforms
```js preview-story
// will be visible when platform web is selected
export const JsPreviewStory = () => html` <demo-element></demo-element> `;
```
```xml story-code
<!-- will be visible when platform android is selected -->
<Button
android:id="@+id/demoElement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android Code"
style="@style/Widget.Demo.Element"
/>
```
```swift story-code
// will be visible when platform ios is selected
import Demo.Element
let card = DemoElement()
```
## HTML Story
````md

View File

@@ -1,4 +1,3 @@
# Presets >> Launch || 20
- [Preset](./preset/)
- [Custom Elements](./custom-elements/)

View File

@@ -1,4 +1,3 @@
# Presets >> Search || 10
- [Preset](./preset/)
- [Custom Elements](./custom-elements/)

View File

@@ -3,6 +3,111 @@
The Plugins Manager replaces the specific registration/execution (with options) in a given plugin system by an intend to use a plugin (with these options).
This allows your users to adjust the options before actually applying the plugins.
## Setup
1. Install npm package
```bash
npm i plugins-manager
```
2. Change your public API from an array of plugin "instances" to an array of setup functions
```diff
import myPlugin from 'my-plugin';
+ import { addPlugin } from 'plugins-manager';
export default {
- plugins: [myPlugin],
+ setupPlugins: [addPlugin(myPlugin)]
}
```
3. Convert setup function to plugins
```js
import { applyPlugins } from 'plugins-manager';
const finalConfig = applyPlugins(config); // "converts" setupPlugins to plugins
// work with plugins or pass it on to another tool
const bundle = await rollup(finalConfig);
```
## Usage
As you users in most cases you will need to either add or adjust a given plugin in a config file.
👉 `my-tool.config.js`
```js
import { addPlugin, adjustPluginOptions } from 'plugins-manager';
import json from '@rollup/plugin-json';
import { nodeResolve } from '@rollup/plugin-node-resolve';
export default {
setupPlugins: [
// add a new plugin with optional plugin options
addPlugin(json, {
/* ... */
}),
// adjust the options of a plugin that is already registered
adjustPluginOptions(nodeResolve, {
/* ... */
}),
],
};
```
## Plugins can be functions or classes
### Function Plugins
```js
function myPlugin({ lastName: 'initial-second' }) {
// ...
}
export default {
setupPlugins: [addPlugin(myPlugin)],
};
// function parameters are type safe
addPlugin(myPlugin, { lastName: 'new name' }); // ts ok
addPlugin(myPlugin, { otherProp: 'new name' }); // ts error
```
### Class Plugins
The options are passed to the constructor.
```js
/**
* @typedef {object} MyClassOptions
* @property {string} lastName
*/
class MyClass {
/** @type {MyClassOptions} */
options = {
lastName: 'initial-second',
};
/**
* @param {Partial<MyClassOptions>} options
*/
constructor(options = {}) {
this.options = { ...this.options, ...options };
}
// ...
}
export default {
setupPlugins: [addPlugin(MyClass)],
};
// constructor parameters are type safe
addPlugin(MyClass, { lastName: 'new name' }); // ts ok
addPlugin(MyClass, { otherProp: 'new name' }); // ts error
```
## Problem
Many plugin systems require you to either execute a plugin function like in `rollup`.
@@ -48,18 +153,14 @@ This means if you wish to define default plugins and allow your user to override
The plugins manager lets you orchestrate a set of "meta plugins" which are defined by
- name
- plugin
- options
- plugin (class or function)
- it's options
```js
import beep from '@rollup/plugin-beep';
import url from '@rollup/plugin-url';
let metaPlugins = [
{ name: 'beep', plugin: beep },
{ name: 'url', plugin: url, options: { limit: 10000 } },
];
let metaPlugins = [{ plugin: beep }, { plugin: url, options: { limit: 10000 } }];
```
This array can be modified by adding/removing or adjusting options.
@@ -94,16 +195,13 @@ export default {
### Adding Helpers
Doing array manipulations is kinda error-prone so we offer encourage to use an array of setup function. Where as each setup function can either add a new plugin (with a unique name) or adjust an already existing plugin.
Doing array manipulations is kinda error-prone so we encourage to use an array of setup function. Where as each setup function can either add a new plugin (with a unique name) or adjust an already existing plugin.
```js
import { addPlugin, adjustPluginOptions } from 'plugins-manager';
const systemSetupFunctions = [
addPlugin({ name: 'first', plugin: first }),
addPlugin({ name: 'second', plugin: second }),
];
const userSetupFunctions = [adjustPluginOptions('first', { my: 'options' })];
const systemSetupFunctions = [addPlugin(first), addPlugin(second)];
const userSetupFunctions = [adjustPluginOptions(first, { my: 'options' })];
```
Arrays of functions can by merged like so
@@ -115,9 +213,9 @@ const finalSetupFunctions = [...systemSetupFunctions, ...userSetupFunctions];
and then converted to the final output.
```js
import { metaPluginsToRollupPlugins } from 'plugins-manager';
import { applyPlugins } from 'plugins-manager';
const plugins = metaPluginsToRollupPlugins(finalSetupFunctions, metaPlugins);
const plugins = applyPlugins(finalSetupFunctions, metaPlugins);
```
## Adding a Plugin
@@ -133,18 +231,27 @@ By default it adds at the bottom.
import json from '@rollup/plugin-json';
import { addPlugin } from 'plugins-manager';
const userSetupFunctions = [
addPlugin({ name: 'json', plugin: json, options: { preferConst: true } }),
];
const userSetupFunctions = [addPlugin(json, { preferConst: true })];
```
Example usage:
```js
addPlugin({ name: 'json', plugin: json }); // Add at the bottom (default)
addPlugin({ name: 'json', plugin: json, location: 'top' }); // Add at the top/beginning of the array
addPlugin({ name: 'json', plugin: json, location: 'beep' }); // Add after (default) plugin 'beep'
addPlugin({ name: 'json', plugin: json, location: 'beep', how: 'before' }); // Add before plugin 'beep'
addPlugin(json); // Add at the bottom (default)
addPlugin(json, {}, { location: 'top' }); // Add at the top/beginning of the array
addPlugin(json, {}, { location: beep }); // Add after (default) plugin 'beep'
addPlugin(json, {}, { location: beep, how: 'before' }); // Add before plugin 'beep'
```
This is type safe and typescript will throw an error if you pass the wrong type.
```js
function myPlugin({ myFlag = false } = {}) {
// ...
}
addPlugin(myPlugin, { myFlag: true }); // ts ok
addPlugin(myPlugin, { notExisting: true }); // ts error
```
## Adjusting Plugin Options
@@ -154,12 +261,14 @@ Adjusting options means to either
- flatly merge objects (e.g. only the first level will be preserved)
- calling a function to do the merge yourself
- setting the raw value (if not an object or function)
- you need to have a reference to the plugin (which is used to auto complete the available options via typescript)
```js
import json from '@rollup/plugin-json';
import { adjustPluginOptions } from 'plugins-manager';
const userSetupFunctions = [
adjustPluginOptions('json', { preferConst: false, anotherOption: 'format' }),
adjustPluginOptions(json, { preferConst: false, anotherOption: 'format' }),
];
```
@@ -167,36 +276,53 @@ Example usage:
```js
// given
addPlugin({
name: 'json',
plugin: json,
options: {
other: {
nested: 'other.nested',
nested2: 'other.nested2',
},
main: true,
addPlugin(json, {
other: {
nested: 'other.nested',
nested2: 'other.nested2',
},
main: true,
});
// merge objects flately
adjustPluginOptions('json', { other: { nested: '--overwritten--' } });
adjustPluginOptions(json, { other: { nested: '--overwritten--' } });
// resulting options = { other: { nested: '--overwritten--' }, main: true }
// NOTE: nested2 is removed
// merge via function
adjustPluginOptions('json', config => ({ other: { ...config.other, nested: '--overwritten--' } }));
adjustPluginOptions(json, config => ({ other: { ...config.other, nested: '--overwritten--' } }));
// resulting options = { other: { nested: '--overwritten--', nested2: 'other.nested2' }, main: true }
// merge via function to override full options
adjustPluginOptions('json', config => ({ only: 'this' }));
adjustPluginOptions(json, config => ({ only: 'this' }));
// resulting options = { only: 'this' }
// setting a raw value
adjustPluginOptions('json', false);
adjustPluginOptions(json, false);
// resulting options = false
```
This is type safe and typescript will throw an error if you pass the wrong type.
```js
function myPlugin({ myFlag = false } = {}) {
// ...
}
adjustPluginOptions(myPlugin, { myFlag: true }); // ts ok
adjustPluginOptions(myPlugin, { notExisting: true }); // ts error
```
## Remove Plugin
Sometimes you would like to remove a default plugin from the config.
```js
export default {
setupPlugins: [removePlugin(json)],
};
```
## Converting metaPlugins to an Actual Plugin
To execute all setup function you can use this little helper
@@ -227,25 +353,9 @@ Rollup has a more specific helper that handles
Note: if you provide `config.plugins` then it will return that directly ignoring `setupPlugins`
```js
import { metaConfigToRollupConfig } from 'plugins-manager';
import { applyPlugins } from 'plugins-manager';
const finalConfig = metaConfigToRollupConfig(currentConfig, defaultMetaPlugins);
```
Web Dev Server has a more specific helper that handles
- `config.setupPlugins`
- `config.setupRollupPlugins`
Note: if you provide `config.plugins` then it will return that directly ignoring `setupPlugins` and `setupRollupPlugins`
```js
import { metaConfigToWebDevServerConfig } from 'plugins-manager';
import { fromRollup } from '@web/dev-server-rollup';
const finalConfig = metaConfigToWebDevServerConfig(currentConfig, defaultMetaPlugins, {
rollupWrapperFunction: fromRollup,
});
const finalConfig = applyPlugins(currentConfig, defaultMetaPlugins);
```
Eleventy

View File

@@ -42,11 +42,13 @@ eleventyExcludeFromCollections: true
<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{% raw %}{% for page in collections.all %}
{%- if page.url !== '/404.html' -%}
<url>
<loc>{{ rocketConfig.absoluteBaseUrl }}{{ page.url | url }}</loc>
<lastmod>{{ page.date.toISOString() }}</lastmod>
<changefreq>{{ page.data.changeFreq if page.data.changeFreq else "monthly" }}</changefreq>
</url>
{%- endif -%}
{% endfor %}{% endraw %}
</urlset>
```

View File

@@ -29,14 +29,15 @@
"postinstall": "npm run setup",
"release": "changeset publish && yarn format",
"rocket:build": "node packages/cli/src/cli.js build",
"rocket:upgrade": "node packages/cli/src/cli.js upgrade",
"search": "node packages/cli/src/cli.js search",
"setup": "npm run setup:ts-configs && npm run build:packages",
"setup:patches": "npx patch-package",
"setup:ts-configs": "node scripts/generate-ts-configs.mjs",
"prestart": "yarn analyze",
"start": "node packages/cli/src/cli.js start",
"xprestart": "yarn analyze",
"start": "node --trace-warnings packages/cli/src/cli.js start",
"test": "yarn test:node && yarn test:web",
"test:node": "mocha \"packages/*/test-node/**/*.test.{ts,js,mjs,cjs}\" --timeout 5000 --reporter dot --exit",
"test:node": "mocha \"packages/*/test-node/**/*.test.{ts,js,mjs,cjs}\" -- --timeout 5000 --reporter dot --exit",
"test:web": "web-test-runner",
"types": "run-s types:clear types:copy types:build",
"types:build": "tsc --build",
@@ -62,7 +63,7 @@
"@typescript-eslint/parser": "^4.13.0",
"@web/test-runner": "^0.12.2",
"@web/test-runner-commands": "^0.4.0",
"@web/test-runner-playwright": "^0.8.0",
"@web/test-runner-playwright": "^0.8.8",
"cem-plugin-readme": "^0.1.3",
"chai": "^4.2.0",
"concurrently": "^5.3.0",
@@ -80,6 +81,7 @@
"onchange": "^7.1.0",
"prettier": "^2.2.1",
"prettier-plugin-package": "^1.3.0",
"publish-docs": "^0.1.2",
"puppeteer": "^9.0.0",
"remark-emoji": "^2.1.0",
"rimraf": "^3.0.2",

View File

@@ -1,5 +1,38 @@
# @rocket/blog
## 0.4.0
### Minor Changes
- 70bb7a1: BREAKING CHANGE: Update to latest plugins manager to get type safe options
There is no longer a name string as a key for a plugin. It is identified by it's function/class. You will need to adjust your code if you are adding or adjusting plugins.
```diff
- addPlugin({ name: 'my-plugin', plugin: myPlugin, options: { myFlag: true }, location: 'top' });
+ addPlugin(myPlugin, { myFlag: true }, { location: 'top' });
- adjustPluginOptions('my-plugin', { myFlag: true });
+ adjustPluginOptions(myPlugin, { myFlag: true });
```
For more details please see the [Changelog](https://github.com/modernweb-dev/rocket/blob/main/packages/plugins-manager/CHANGELOG.md#030) of the plugins-manager package.
### Patch Changes
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- plugins-manager@0.3.0
## 0.3.3
### Patch Changes
- e1089c5: add title to blog page
## 0.3.2
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@rocket/blog",
"version": "0.3.2",
"version": "0.4.0",
"publishConfig": {
"access": "public"
},
@@ -38,6 +38,6 @@
"testing"
],
"dependencies": {
"plugins-manager": "^0.2.4"
"plugins-manager": "^0.3.0"
}
}

View File

@@ -1,3 +1,6 @@
{% if title %}
<h1>{{title}}</h1>
{% endif %}
{% if cover_image %}
<img src="{{ cover_image | url }}" alt="">
{% endif %}

View File

@@ -1,25 +0,0 @@
<rocket-navigation>
<ul>
<li class="current">
<h3>Headings</h3>
{{ collections[section] | rocketPageAnchors({ title: title }) | rocketNavToHtml({
listItemClass: "menu-item",
activeListItemClass: "current",
activeKey: eleventyNavigation.key
}) | safe }}
</li>
</ul>
<div class="sidebar-tags">
<h3>Date</h3>
<div>{{ page.date.toDateString() }}</div>
</div>
<div class="sidebar-tags">
<h3>Tags</h3>
<div class="tags">
{% for tag in tags %}
<span class="tag">{{tag}}</span>
{% endfor %}
</div>
</div>
{% include 'partials/mobile-sidebar-bottom.njk' %}
</rocket-navigation>

View File

@@ -1,19 +1 @@
<div class="articles">
{% for post in posts %}
{% if post.data.published %}
<article>
{% if post.data.cover_image %}
<a href="{{ post.url | url }}" class="thumbnail" style="background: url({{ post.data.cover_image | url }});">
</a>
{% endif %}
<div class="content">
<h2>
<a href="{{ post.url | url }}">{{ post.data.title }}</a>
</h2>
<p>{{ post.data.description }}</p>
<a class="read" href="{{ post.url | url }}">...read more</a>
</div>
</article>
{% endif %}
{% endfor %}
</div>
<web-menu name="article-overview"></web-menu>

View File

@@ -1 +1,9 @@
<link rel="stylesheet" href="{{ '/_assets/rocket-blog.css' | asset | url }}">
{%- if layout == 'layout-blog-overview' -%}
<style>
.articles article .thumbnail {
background-size: cover;
background-position: center;
}
</style>
{%- endif -%}

View File

@@ -1,52 +1,52 @@
import path from 'path';
import { fileURLToPath } from 'url';
import { addPlugin } from 'plugins-manager';
// import { addPlugin } from 'plugins-manager';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const SECTION = 'blog';
const POST_COLLECTION = 'posts';
// const SECTION = 'blog';
// const POST_COLLECTION = 'posts';
export function rocketBlog({ section = SECTION, postCollection = POST_COLLECTION } = {}) {
const isHiddenCollection = item => ['-', '_'].includes(item.charAt(0));
const isVisibleCollection = item => !isHiddenCollection(item);
const isNotPostCollection = collection => collection !== postCollection;
export function rocketBlog() {
// const isHiddenCollection = item => ['-', '_'].includes(item.charAt(0));
// const isVisibleCollection = item => !isHiddenCollection(item);
// const isNotPostCollection = collection => collection !== postCollection;
const eleventyPluginRocketBlog = {
configFunction: eleventyConfig => {
eleventyConfig.addCollection('posts', collection => {
/*
// It's not working beacuse it's a paginated collection.
const headerDocs = eleventyConfig.collections.header(collection);
headerDocs.filter(page => page.data.section === section).forEach(page => {
page.data.layout = 'blog';
});
*/
if (section === postCollection) {
throw new Error("Rocket blog: section and postCollection couldn't be equal");
}
if (!eleventyConfig.collections[section]) {
const collectionKeys = Object.keys(eleventyConfig.collections);
const availableCollections = collectionKeys
.filter(isVisibleCollection)
.filter(isNotPostCollection);
throw new Error(
`Rocket blog: Collection '${section}' not found. Aviable colections: ${availableCollections.join(
', ',
)}`,
);
}
// const eleventyPluginRocketBlog = {
// configFunction: eleventyConfig => {
// eleventyConfig.addCollection('posts', collection => {
// /*
// // It's not working beacuse it's a paginated collection.
// const headerDocs = eleventyConfig.collections.header(collection);
// headerDocs.filter(page => page.data.section === section).forEach(page => {
// page.data.layout = 'blog';
// });
// */
// if (section === postCollection) {
// throw new Error("Rocket blog: section and postCollection couldn't be equal");
// }
// if (!eleventyConfig.collections[section]) {
// const collectionKeys = Object.keys(eleventyConfig.collections);
// const availableCollections = collectionKeys
// .filter(isVisibleCollection)
// .filter(isNotPostCollection);
// throw new Error(
// `Rocket blog: Collection '${section}' not found. Aviable colections: ${availableCollections.join(
// ', ',
// )}`,
// );
// }
const posts = eleventyConfig.collections[section](collection);
posts.forEach(page => {
page.data.layout = 'layout-blog-details';
});
return posts;
});
},
};
// const posts = eleventyConfig.collections[section](collection);
// posts.forEach(page => {
// page.data.layout = 'layout-blog-details';
// });
// return posts;
// });
// },
// };
return {
path: path.resolve(__dirname),
setupEleventyPlugins: [addPlugin({ name: 'rocket-blog', plugin: eleventyPluginRocketBlog })],
// setupEleventyPlugins: [addPlugin({ name: 'rocket-blog', plugin: eleventyPluginRocketBlog })],
};
}

View File

@@ -1,5 +1,22 @@
# @rocket/building-rollup
## 0.4.0
### Minor Changes
- 70bb7a1: BREAKING CHANGE: Update to latest plugins manager to get type safe options
There is no longer a name string as a key for a plugin. It is identified by it's function/class. You will need to adjust your code if you are adding or adjusting plugins.
```diff
- addPlugin({ name: 'my-plugin', plugin: myPlugin, options: { myFlag: true }, location: 'top' });
+ addPlugin(myPlugin, { myFlag: true }, { location: 'top' });
- adjustPluginOptions('my-plugin', { myFlag: true });
+ adjustPluginOptions(myPlugin, { myFlag: true });
```
For more details please see the [Changelog](https://github.com/modernweb-dev/rocket/blob/main/packages/plugins-manager/CHANGELOG.md#030) of the plugins-manager package.
## 0.3.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@rocket/building-rollup",
"version": "0.3.1",
"version": "0.4.0",
"publishConfig": {
"access": "public"
},

View File

@@ -2,13 +2,13 @@ import resolve from '@rollup/plugin-node-resolve';
import { terser } from 'rollup-plugin-terser';
import babelPkg from '@rollup/plugin-babel';
import { metaConfigToRollupConfig } from 'plugins-manager';
import { applyPlugins } from 'plugins-manager';
const { babel } = babelPkg;
export function createBasicConfig(userConfig) {
const { config, metaPlugins } = createBasicMetaConfig(userConfig);
return metaConfigToRollupConfig(config, metaPlugins);
return applyPlugins(config, metaPlugins);
}
export function createBasicMetaConfig(userConfig = { output: {} }) {
@@ -39,14 +39,12 @@ export function createBasicMetaConfig(userConfig = { output: {} }) {
let metaPlugins = [
{
name: 'node-resolve',
plugin: resolve,
options: {
moduleDirectories: ['node_modules', 'web_modules'],
},
},
{
name: 'babel',
plugin: babel,
options: {
babelHelpers: 'bundled',
@@ -73,7 +71,6 @@ export function createBasicMetaConfig(userConfig = { output: {} }) {
},
},
{
name: 'terser',
plugin: terser,
},
];

View File

@@ -1,10 +1,11 @@
import { createSpaMetaConfig } from './createSpaConfig.js';
import { adjustPluginOptions, metaConfigToRollupConfig } from 'plugins-manager';
import { adjustPluginOptions, applyPlugins } from 'plugins-manager';
import { rollupPluginHTML } from '@web/rollup-plugin-html';
export function createMpaConfig(userConfig) {
const { config, metaPlugins } = createMpaMetaConfig(userConfig);
const final = metaConfigToRollupConfig(config, metaPlugins);
const final = applyPlugins(config, metaPlugins);
return final;
}
@@ -12,7 +13,7 @@ export function createMpaMetaConfig(userConfig = { output: {}, setupPlugins: []
const { config, metaPlugins } = createSpaMetaConfig(userConfig);
config.setupPlugins = [
adjustPluginOptions('html', {
adjustPluginOptions(rollupPluginHTML, {
flattenOutput: false,
}),
...config.setupPlugins,

View File

@@ -3,13 +3,13 @@ import { terser } from 'rollup-plugin-terser';
import babelPkg from '@rollup/plugin-babel';
import replace from '@rollup/plugin-replace';
import { metaConfigToRollupConfig } from 'plugins-manager';
import { applyPlugins } from 'plugins-manager';
const { babel } = babelPkg;
export function createServiceWorkerConfig(userConfig) {
const { config, metaPlugins } = createServiceWorkerMetaConfig(userConfig);
return metaConfigToRollupConfig(config, metaPlugins);
return applyPlugins(config, metaPlugins);
}
export function createServiceWorkerMetaConfig(userConfig = { output: {} }) {
@@ -33,21 +33,19 @@ export function createServiceWorkerMetaConfig(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'),
preventAssignment: true,
},
},
{
name: 'babel',
plugin: babel,
options: {
babelHelpers: 'bundled',
@@ -74,7 +72,6 @@ export function createServiceWorkerMetaConfig(userConfig = { output: {} }) {
},
},
{
name: 'terser',
plugin: terser,
options: {
mangle: {

View File

@@ -1,13 +1,13 @@
import { rollupPluginHTML } from '@web/rollup-plugin-html';
import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets';
import { polyfillsLoader } from '@web/rollup-plugin-polyfills-loader';
import { metaConfigToRollupConfig } from 'plugins-manager';
import { applyPlugins } from 'plugins-manager';
import { createBasicMetaConfig } from './createBasicConfig.js';
export function createSpaConfig(userConfig) {
const { config, metaPlugins } = createSpaMetaConfig(userConfig);
return metaConfigToRollupConfig(config, metaPlugins);
return applyPlugins(config, metaPlugins);
}
export function createSpaMetaConfig(userConfig = { output: {} }) {
@@ -30,7 +30,6 @@ export function createSpaMetaConfig(userConfig = { output: {} }) {
const spaMetaPlugins = [
...metaPlugins,
{
name: 'html',
plugin: rollupPluginHTML,
options: {
rootDir,
@@ -38,11 +37,9 @@ export function createSpaMetaConfig(userConfig = { output: {} }) {
},
},
{
name: 'import-meta-assets',
plugin: importMetaAssets,
},
{
name: 'polyfills-loader',
plugin: polyfillsLoader,
options: {
polyfills: {},

View File

@@ -1,5 +1,44 @@
# @rocket/cli
## 0.10.0
### Minor Changes
- 70bb7a1: BREAKING CHANGE: Update to latest plugins manager to get type safe options
There is no longer a name string as a key for a plugin. It is identified by it's function/class. You will need to adjust your code if you are adding or adjusting plugins.
```diff
- addPlugin({ name: 'my-plugin', plugin: myPlugin, options: { myFlag: true }, location: 'top' });
+ addPlugin(myPlugin, { myFlag: true }, { location: 'top' });
- adjustPluginOptions('my-plugin', { myFlag: true });
+ adjustPluginOptions(myPlugin, { myFlag: true });
```
For more details please see the [Changelog](https://github.com/modernweb-dev/rocket/blob/main/packages/plugins-manager/CHANGELOG.md#030) of the plugins-manager package.
### Patch Changes
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- Updated dependencies [70bb7a1]
- plugins-manager@0.3.0
- @rocket/eleventy-plugin-mdjs-unified@0.6.0
- @rocket/building-rollup@0.4.0
## 0.9.11
### Patch Changes
- 7301a0f: Pass on rocketConfig to the eleventy function to enable conditional configurations/filters
- 42418f2: Disable the service worker for local development
- 5ac6aa6: Set the encoding of the simulator to utf8 via a html meta tag
## 0.9.10
### Patch Changes

View File

@@ -1,10 +1,20 @@
const { setComputedConfig, getComputedConfig } = require('./src/public/computedConfig.cjs');
const { generateEleventyComputed } = require('./src/public/generateEleventyComputed.cjs');
const {
generateEleventyComputed,
LayoutPlugin,
SectionPlugin,
SocialMediaImagePlugin,
JoiningBlocksPlugin,
} = require('./src/public/generateEleventyComputed.cjs');
const { createSocialImage } = require('./src/public/createSocialImage.cjs');
module.exports = {
setComputedConfig,
getComputedConfig,
generateEleventyComputed,
LayoutPlugin,
SectionPlugin,
SocialMediaImagePlugin,
JoiningBlocksPlugin,
createSocialImage,
};

View File

@@ -1,3 +1,13 @@
/** @typedef {import('@rocket/cli/types/main').RocketCliOptions} RocketCliOptions */
export { setComputedConfig, getComputedConfig } from './src/public/computedConfig.cjs';
export {
generateEleventyComputed,
LayoutPlugin,
SectionPlugin,
SocialMediaImagePlugin,
JoiningBlocksPlugin,
} from './src/public/generateEleventyComputed.cjs';
export { createSocialImage } from './src/public/createSocialImage.cjs';
export { RocketCli } from './src/RocketCli.js';

View File

@@ -1,6 +1,6 @@
{
"name": "@rocket/cli",
"version": "0.9.10",
"version": "0.10.0",
"publishConfig": {
"access": "public"
},
@@ -57,10 +57,9 @@
"dependencies": {
"@11ty/eleventy": "^0.11.1",
"@11ty/eleventy-img": "^0.9.0",
"@rocket/building-rollup": "^0.3.1",
"@rocket/building-rollup": "^0.4.0",
"@rocket/core": "^0.1.2",
"@rocket/eleventy-plugin-mdjs-unified": "^0.5.2",
"@rocket/eleventy-rocket-nav": "^0.3.0",
"@rocket/eleventy-plugin-mdjs-unified": "^0.6.0",
"@rollup/plugin-babel": "^5.2.2",
"@rollup/plugin-node-resolve": "^11.0.1",
"@web/config-loader": "^0.1.3",
@@ -71,8 +70,9 @@
"command-line-args": "^5.1.1",
"command-line-usage": "^6.1.1",
"fs-extra": "^9.0.1",
"gray-matter": "^4.0.3",
"micromatch": "^4.0.2",
"plugins-manager": "^0.2.4",
"plugins-manager": "^0.3.0",
"slash": "^3.0.0",
"utf8": "^3.0.0",
"workbox-window": "^6.1.5"

View File

@@ -4,4 +4,6 @@
window.__rocketServiceWorkerUrl = '{{ rocketServiceWorkerUrl | url }}';
</script>
{% if rocketConfig.command == 'build' %}
<script type="module" inject-service-worker="" src="{{ '/_assets/scripts/registerServiceWorker.js' | asset | url }}"></script>
{% endif %}

View File

@@ -1,4 +1,4 @@
<a class="logo-link" href="{{ '/' | url }}">
<img src="{{ '/_assets/logo.svg' | asset | url }}" alt="{{ site.logoAlt }}" />
<span class="sr-only">{{ site.name }}</span>
<span>{{ site.name }}</span>
</a>

View File

@@ -1,6 +1,8 @@
<html theme="light" platform="web" lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="menu:exclude" content="true">
<meta charset="utf-8">
<style type="text/css">
body {
margin: 0;

View File

@@ -5,6 +5,7 @@ import { rollup } from 'rollup';
import fs from 'fs-extra';
import path from 'path';
import { copy } from '@web/rollup-plugin-copy';
import { rollupPluginHTML } from '@web/rollup-plugin-html';
import { createMpaConfig, createServiceWorkerConfig } from '@rocket/building-rollup';
import { addPlugin, adjustPluginOptions } from 'plugins-manager';
@@ -25,18 +26,14 @@ async function buildAndWrite(config) {
async function productionBuild(config) {
const defaultSetupPlugins = [
addPlugin({
name: 'copy',
plugin: copy,
options: {
patterns: ['!(*.md|*.html)*', '_merged_assets/_static/**/*'],
rootDir: config.outputDevDir,
},
addPlugin(copy, {
patterns: ['!(*.md|*.html)*', '_merged_assets/_static/**/*'],
rootDir: config.outputDevDir,
}),
];
if (config.pathPrefix) {
defaultSetupPlugins.push(
adjustPluginOptions('html', { absolutePathPrefix: config.pathPrefix }),
adjustPluginOptions(rollupPluginHTML, { absolutePathPrefix: config.pathPrefix }),
);
}

View File

@@ -298,7 +298,7 @@ export class RocketCli {
async cleanup() {
setComputedConfig({});
if (this.eleventy) {
this.eleventy.finish();
// this.eleventy.finish();
// await this.eleventy.stopWatch();
}
this.stop();

View File

@@ -1,11 +1,61 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { startDevServer } from '@web/dev-server';
import { fromRollup } from '@web/dev-server-rollup';
import { metaConfigToWebDevServerConfig } from 'plugins-manager';
import { executeSetupFunctions } from 'plugins-manager';
/** @typedef {import('../types/main').RocketCliOptions} RocketCliOptions */
/** @typedef {import('@web/dev-server').DevServerConfig} DevServerConfig */
/**
* @param {any} config
* @param {MetaPluginWrapable[]} metaPlugins
* @param {object} [options]
* @param {function | null} [options.rollupWrapperFunction]
*/
export function metaConfigToWebDevServerConfig(
config,
metaPlugins,
{ rollupWrapperFunction = null } = {},
) {
if (config.plugins) {
delete config.setupPlugins;
delete config.setupRollupPlugins;
return config;
}
const metaPluginsNoWrap = metaPlugins.map(pluginObj => {
pluginObj.__noWrap = true;
return pluginObj;
});
const rollupPlugins = /** @type {MetaPluginWrapable[]} */ (executeSetupFunctions(
config.setupRollupPlugins,
[...metaPluginsNoWrap],
));
const wrappedRollupPlugins = rollupPlugins.map(pluginObj => {
if (typeof rollupWrapperFunction === 'function' && pluginObj.__noWrap !== true) {
pluginObj.plugin = rollupWrapperFunction(pluginObj.plugin);
}
return pluginObj;
});
const _metaPlugins = executeSetupFunctions(config.setupPlugins, [...wrappedRollupPlugins]);
const plugins = _metaPlugins.map(pluginObj => {
if (pluginObj.options) {
return pluginObj.plugin(pluginObj.options);
} else {
return pluginObj.plugin();
}
});
config.plugins = plugins;
delete config.setupPlugins;
delete config.setupRollupPlugins;
return config;
}
export class RocketStart {
static pluginName = 'RocketStart';
commands = ['start'];

187
packages/cli/src/RocketUpgrade.js Executable file
View File

@@ -0,0 +1,187 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { readdir, rename, writeFile } from 'fs/promises';
import path from 'path';
import { upgrade202109menu } from './upgrades/upgrade202109menu.js';
import { copy } from 'fs-extra';
/** @typedef {import('../types/main').RocketCliOptions} RocketCliOptions */
/** @typedef {import('../types/upgrade').UpgradeFile} UpgradeFile */
/** @typedef {import('../types/upgrade').FolderRename} FolderRename */
/** @typedef {import('../types/upgrade').upgrade} upgrade */
/**
* @param {UpgradeFile} options
* @returns {boolean}
*/
function filterMerged({ relPath }) {
return relPath.startsWith('_merged');
}
/**
*
* @param {object} options
* @param {string} options.rootDir
* @param {string} options.currentDir
* @param {(options: UpgradeFile) => Boolean} [options.filter]
* @returns
*/
async function getAllFiles(options) {
const { rootDir, currentDir, filter = filterMerged } = options;
const entries = await readdir(currentDir, { withFileTypes: true });
/** @type {UpgradeFile[]} */
let files = [];
for (const entry of entries) {
const { name: folderName } = entry;
const currentPath = path.join(currentDir, folderName);
if (entry.isFile()) {
const relPath = path.relative(rootDir, currentPath);
/** @type {UpgradeFile} */
const data = {
path: currentPath,
relPath,
name: path.basename(relPath),
extName: path.extname(relPath),
};
if (!filter(data)) {
files.push(data);
}
}
}
for (const entry of entries) {
const { name: folderName } = entry;
const currentPath = path.join(currentDir, folderName);
if (entry.isDirectory()) {
files = [...files, ...(await getAllFiles({ ...options, currentDir: currentPath }))];
}
}
return files;
}
/**
*
* @param {upgrade} options
*/
async function updateFileSystem({ files, folderRenames }) {
// rename files while not touching folders
for (const file of files) {
if (file.updatedName) {
const newPath = path.join(path.dirname(file.path), file.updatedName);
await rename(file.path, newPath);
}
}
// rename folders
for (const renameObj of folderRenames) {
if (renameObj.fromAbsolute && renameObj.toAbsolute) {
await rename(renameObj.fromAbsolute, renameObj.toAbsolute);
}
}
// update file content
for (const file of files) {
if (file.updatedContent) {
await writeFile(file.updatedPath || file.path, file.updatedContent);
}
}
}
/**
* @param {string} relPath
* @param {FolderRename[]} folderRenames
* @returns {string}
*/
function applyFolderRenames(relPath, folderRenames) {
let newRelPath = relPath;
for (const renameObj of folderRenames) {
if (newRelPath.startsWith(renameObj.from)) {
newRelPath = renameObj.to + newRelPath.slice(renameObj.from.length);
}
}
return newRelPath;
}
export class RocketUpgrade {
static pluginName = 'RocketUpgrade';
commands = ['upgrade'];
/**
* @param {object} options
* @param {RocketCliOptions} options.config
* @param {any} options.argv
*/
async setup({ config, argv }) {
this.__argv = argv;
this.config = config;
}
async upgradeCommand() {
if (!this?.config?._inputDirCwdRelative) {
return;
}
const backupPath = path.join(this.config._inputDirCwdRelative, '..', 'docs_backup');
await copy(this.config._inputDirCwdRelative, backupPath);
console.log(`A backup of your docs folder has been created at ${backupPath}.`);
let files = await getAllFiles({
rootDir: this.config._inputDirCwdRelative,
currentDir: this.config._inputDirCwdRelative,
});
/** @type {FolderRename[]} */
let folderRenames = [];
const upgrade = await upgrade202109menu({ files, folderRenames });
files = upgrade.files;
folderRenames = upgrade.folderRenames;
const orderedFolderRenames = [...folderRenames].sort((a, b) => {
return b.from.split('/').length - a.from.split('/').length;
});
// adjust relPath if there is a new filename
let i = 0;
for (const fileData of files) {
if (fileData.updatedName) {
files[i].updatedRelPath = `${path.dirname(fileData.relPath)}/${fileData.updatedName}`;
}
i += 1;
}
// adjust relPath to consider renamed folders
i = 0;
for (const fileData of files) {
const modifiedPath = applyFolderRenames(
fileData.updatedRelPath || fileData.relPath,
orderedFolderRenames,
);
if (modifiedPath !== fileData.relPath) {
files[i].updatedRelPath = modifiedPath;
}
i += 1;
}
// add an updatedPath if needed
i = 0;
for (const file of files) {
if (file.updatedRelPath) {
files[i].updatedPath = path.join(this.config._inputDirCwdRelative, file.updatedRelPath);
}
i += 1;
}
// create absolute paths for renames
i = 0;
for (const renameObj of folderRenames) {
folderRenames[i].fromAbsolute = path.join(this.config._inputDirCwdRelative, renameObj.from);
folderRenames[i].toAbsolute = path.join(this.config._inputDirCwdRelative, renameObj.to);
i += 1;
}
await updateFileSystem({
files,
folderRenames: orderedFolderRenames,
});
}
}

View File

@@ -21,7 +21,7 @@ parser.prepareWasm(saxWasmBuffer);
* @param {string} link
*/
function isRelativeLink(link) {
if (link.startsWith('http') || link.startsWith('/')) {
if (link.startsWith('http') || link.startsWith('/') || link.includes(':')) {
return false;
}
return true;

View File

@@ -14,8 +14,11 @@ import { readConfig } from '@web/config-loader';
import { RocketStart } from './RocketStart.js';
import { RocketBuild } from './RocketBuild.js';
import { RocketUpgrade } from './RocketUpgrade.js';
import { RocketLint } from './RocketLint.js';
import { webMenu } from '@web/menu';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -42,7 +45,7 @@ function ignore({ src }) {
*/
export async function normalizeConfig(inConfig) {
let config = {
presets: [],
presets: [webMenu()],
setupUnifiedPlugins: [],
setupDevAndBuildPlugins: [],
setupDevPlugins: [],
@@ -50,6 +53,7 @@ export async function normalizeConfig(inConfig) {
setupEleventyPlugins: [],
setupEleventyComputedConfig: [],
setupCliPlugins: [],
setupMenus: [],
eleventy: () => {},
command: 'help',
watch: true,
@@ -98,7 +102,7 @@ export async function normalizeConfig(inConfig) {
try {
const fileConfig = await readConfig('rocket.config', userConfigFile, path.resolve(__configDir));
if (fileConfig) {
config = {
const updatedConfig = {
...config,
...fileConfig,
build: {
@@ -111,12 +115,16 @@ export async function normalizeConfig(inConfig) {
},
imagePresets: config.imagePresets,
};
if (fileConfig.presets) {
updatedConfig.presets = [...config.presets, ...fileConfig.presets];
}
if (fileConfig.imagePresets && fileConfig.imagePresets.responsive) {
config.imagePresets.responsive = {
updatedConfig.imagePresets.responsive = {
...config.imagePresets.responsive,
...fileConfig.imagePresets.responsive,
};
}
config = updatedConfig;
}
} catch (error) {
console.error('Could not read rocket config file', error);
@@ -165,6 +173,9 @@ export async function normalizeConfig(inConfig) {
if (preset.setupCliPlugins) {
config.setupCliPlugins = [...config.setupCliPlugins, ...preset.setupCliPlugins];
}
if (preset.setupMenus) {
config.setupMenus = [...config.setupMenus, ...preset.setupMenus];
}
if (typeof preset.before11ty === 'function') {
config.__before11tyFunctions.push(preset.before11ty);
@@ -174,11 +185,7 @@ export async function normalizeConfig(inConfig) {
config._presetPaths.push(path.resolve(_inputDirCwdRelative));
/** @type {MetaPlugin[]} */
let pluginsMeta = [
{ name: 'RocketStart', plugin: RocketStart },
{ name: 'RocketBuild', plugin: RocketBuild },
{ name: 'RocketLint', plugin: RocketLint },
];
let pluginsMeta = [{ plugin: RocketStart }, { plugin: RocketBuild }, { plugin: RocketLint }, { plugin: RocketUpgrade}];
if (Array.isArray(config.setupCliPlugins)) {
for (const setupFn of config.setupCliPlugins) {

View File

@@ -5,8 +5,10 @@ const { createSocialImage: defaultCreateSocialImage } = require('./createSocialI
const { getComputedConfig } = require('./computedConfig.cjs');
const { executeSetupFunctions } = require('plugins-manager');
function titleMetaPlugin() {
return async data => {
class TitleMetaPlugin {
static dataName = 'titleMeta';
async execute(data) {
if (data.titleMeta) {
return data.titleMeta;
}
@@ -17,29 +19,24 @@ function titleMetaPlugin() {
return titleMetaFromContent;
}
return {};
};
}
}
function titlePlugin() {
return async data => {
class TitlePlugin {
static dataName = 'title';
async execute(data) {
if (data.title) {
return data.title;
}
return data.titleMeta?.title;
};
}
}
function eleventyNavigationPlugin() {
return async data => {
if (data.eleventyNavigation) {
return data.eleventyNavigation;
}
return data.titleMeta?.eleventyNavigation;
};
}
class SectionPlugin {
static dataName = 'section';
function sectionPlugin() {
return async data => {
async execute(data) {
if (data.section) {
return data.section;
}
@@ -52,11 +49,17 @@ function sectionPlugin() {
return parts[1];
}
}
};
}
}
function layoutPlugin({ defaultLayout = 'layout-default' } = {}) {
return async data => {
class LayoutPlugin {
static dataName = 'layout';
constructor({ defaultLayout = 'layout-default' } = {}) {
this.defaultLayout = defaultLayout;
}
async execute(data) {
if (data.layout) {
return data.layout;
}
@@ -66,22 +69,29 @@ function layoutPlugin({ defaultLayout = 'layout-default' } = {}) {
return 'layout-index';
}
}
return defaultLayout;
};
return this.defaultLayout;
}
}
function socialMediaImagePlugin(args = {}) {
const { createSocialImage = defaultCreateSocialImage, rocketConfig = {} } = args;
class SocialMediaImagePlugin {
static dataName = 'socialMediaImage';
const cleanedUpArgs = { ...args };
delete cleanedUpArgs.createSocialImage;
constructor(args = {}) {
const { createSocialImage = defaultCreateSocialImage, rocketConfig = {} } = args;
return async data => {
this.cleanedUpArgs = { ...args };
delete this.cleanedUpArgs.createSocialImage;
this.rocketConfig = rocketConfig;
this.createSocialImage = createSocialImage;
}
async execute(data) {
if (data.socialMediaImage) {
return data.socialMediaImage;
}
if (rocketConfig.createSocialMediaImages === false) {
if (this.rocketConfig.createSocialMediaImages === false) {
return;
}
@@ -95,15 +105,15 @@ function socialMediaImagePlugin(args = {}) {
const section = data.section ? ' ' + data.section[0].toUpperCase() + data.section.slice(1) : '';
const footer = `${data.site.name}${section}`;
const imgUrl = await createSocialImage({
const imgUrl = await this.createSocialImage({
title,
subTitle,
footer,
section,
...cleanedUpArgs,
...this.cleanedUpArgs,
});
return imgUrl;
};
}
}
function sortByOrder(a, b) {
@@ -146,26 +156,64 @@ async function dirToTree(sourcePath, extra = '') {
return sortedTree;
}
function joiningBlocksPlugin(rocketConfig) {
const { _inputDirCwdRelative } = rocketConfig;
const partialsSource = path.resolve(_inputDirCwdRelative, '_merged_includes');
return async () => {
const joiningBlocks = await dirToTree(partialsSource, '_joiningBlocks');
class JoiningBlocksPlugin {
static dataName = '_joiningBlocks';
constructor(rocketConfig) {
const { _inputDirCwdRelative } = rocketConfig;
this.partialsSource = path.resolve(_inputDirCwdRelative, '_merged_includes');
}
async execute() {
const joiningBlocks = await dirToTree(this.partialsSource, '_joiningBlocks');
return joiningBlocks;
};
}
}
/**
* Removes the `xx--` prefix that is used for ordering
*
* @returns {string}
*/
class PermalinkPlugin {
static dataName = 'permalink';
execute(data) {
if (data.permalink) {
return data.permalink;
}
let filePath = data.page.filePathStem.replace(/[0-9]+--/g, '');
return filePath.endsWith('index') ? `${filePath}.html` : `${filePath}/index.html`;
}
}
/**
* @returns {Number}
*/
class MenuOrderPlugin {
static dataName = 'menu.order';
execute(data) {
const matches = data.page.fileSlug.match(/([0-9]+)--/);
if (matches) {
return parseInt(matches[1]);
}
return 0;
}
}
function generateEleventyComputed() {
const rocketConfig = getComputedConfig();
let metaPlugins = [
{ name: 'titleMeta', plugin: titleMetaPlugin },
{ name: 'title', plugin: titlePlugin },
{ name: 'eleventyNavigation', plugin: eleventyNavigationPlugin },
{ name: 'section', plugin: sectionPlugin },
{ name: 'socialMediaImage', plugin: socialMediaImagePlugin, options: { rocketConfig } },
{ name: '_joiningBlocks', plugin: joiningBlocksPlugin, options: rocketConfig },
{ name: 'layout', plugin: layoutPlugin },
{ plugin: TitleMetaPlugin, options: {} }, // TODO: remove after search & social media are standalone
{ plugin: TitlePlugin, options: {} }, // TODO: remove after search & social media are standalone
{ plugin: SectionPlugin, options: {} }, // TODO: remove this
{ plugin: SocialMediaImagePlugin, options: { rocketConfig } }, // TODO: convert to standalone tool that can work with html
{ plugin: JoiningBlocksPlugin, options: rocketConfig },
{ plugin: LayoutPlugin, options: {} },
{ plugin: PermalinkPlugin, options: {} },
{ plugin: MenuOrderPlugin, options: {} },
];
const finalMetaPlugins = executeSetupFunctions(
@@ -176,13 +224,23 @@ function generateEleventyComputed() {
const eleventyComputed = {};
for (const pluginObj of finalMetaPlugins) {
if (pluginObj.options) {
eleventyComputed[pluginObj.name] = pluginObj.plugin(pluginObj.options);
const inst = new pluginObj.plugin(pluginObj.options);
eleventyComputed[inst.constructor.dataName] = inst.execute.bind(inst);
} else {
eleventyComputed[pluginObj.name] = pluginObj.plugin();
const inst = new pluginObj.plugin();
eleventyComputed[inst.constructor.dataName] = inst.execute.bind(inst);
}
}
return eleventyComputed;
}
module.exports = { generateEleventyComputed };
module.exports = {
generateEleventyComputed,
LayoutPlugin,
PermalinkPlugin,
MenuOrderPlugin,
SectionPlugin,
SocialMediaImagePlugin,
JoiningBlocksPlugin,
};

View File

@@ -1,5 +1,6 @@
const eleventyPluginMdjsUnified = require('@rocket/eleventy-plugin-mdjs-unified');
const eleventyRocketNav = require('@rocket/eleventy-rocket-nav');
const remark2rehype = require('remark-rehype');
const { getComputedConfig } = require('../public/computedConfig.cjs');
const rocketFilters = require('../eleventy-plugins/rocketFilters.cjs');
@@ -9,7 +10,7 @@ const { adjustPluginOptions } = require('plugins-manager');
const image = require('./mdjsImageHandler.cjs');
const defaultSetupUnifiedPlugins = [
adjustPluginOptions('remark2rehype', {
adjustPluginOptions(remark2rehype, {
handlers: {
image,
},
@@ -23,31 +24,19 @@ module.exports = function (eleventyConfig) {
let metaPlugins = [
{
name: 'rocket-filters',
plugin: rocketFilters,
options: { _inputDirCwdRelative },
},
{
name: 'rocket-copy',
plugin: rocketCopy,
options: { _inputDirCwdRelative },
},
{
name: 'eleventy-plugin-mdjs-unified',
plugin: eleventyPluginMdjsUnified,
options: {
setupUnifiedPlugins: [...defaultSetupUnifiedPlugins, ...config.setupUnifiedPlugins],
},
},
{
name: 'eleventy-rocket-nav',
plugin: eleventyRocketNav,
},
{
name: 'rocket-collections',
plugin: rocketCollections,
options: { _inputDirCwdRelative },
},
];
if (Array.isArray(config.setupEleventyPlugins)) {
@@ -69,7 +58,7 @@ module.exports = function (eleventyConfig) {
}
if (config.eleventy) {
const returnValue = config.eleventy(eleventyConfig);
const returnValue = config.eleventy(eleventyConfig, config);
if (returnValue) {
const returnString = JSON.stringify(returnValue, null, 2);
const msg = [

View File

@@ -0,0 +1,169 @@
import { readFile } from 'fs/promises';
import matter from 'gray-matter';
/** @typedef {import('@rocket/cli/types/upgrade').upgrade} upgrade */
/**
*
* @param {upgrade} options
*/
export async function upgrade202109menu({ files, folderRenames }) {
let i = 0;
const updatedFolderRenames = [...folderRenames];
for (const fileData of files) {
if (fileData.extName === '.md') {
const content = (await readFile(fileData.path)).toString();
const lines = content.split('\n');
const { title, lineNumber } = extractTitle(content);
let order = 0;
if (title && lineNumber >= 0) {
const parsedTitle = parseTitle(title);
order = parsedTitle.order;
lines[lineNumber] = `# ${parsedTitle.title}`;
files[i].updatedContent = lines.join('\n');
}
if (lines[0] === '---') {
const fmObj = matter(content);
if (fmObj.data.eleventyNavigation) {
const eleventyNav = fmObj.data.eleventyNavigation;
if (eleventyNav.order) {
order = eleventyNav.order;
delete fmObj.data.eleventyNavigation.order;
}
if (eleventyNav.key) {
fmObj.data.menu = { ...fmObj.data.menu, linkText: eleventyNav.key };
delete fmObj.data.eleventyNavigation.key;
}
if (eleventyNav.parent) {
delete fmObj.data.eleventyNavigation.parent;
}
if (Object.keys(eleventyNav).length === 0) {
delete fmObj.data.eleventyNavigation;
}
}
if (!title && fmObj.data.title) {
fmObj.content = `\n# ${fmObj.data.title}\n${fmObj.content}`;
delete fmObj.data.title;
}
if (fmObj.data.eleventyExcludeFromCollections) {
fmObj.data.menu = { ...fmObj.data.menu, exclude: true };
delete fmObj.data.eleventyExcludeFromCollections;
}
if (Object.keys(fmObj.data).length > 0) {
files[i].updatedContent = matter.stringify(fmObj.content, fmObj.data);
}
}
if (order !== 0) {
if (fileData.relPath.toLowerCase().endsWith('index.md')) {
const pathParts = fileData.relPath.split('/');
const originDirParts = [...pathParts];
originDirParts.pop();
pathParts[pathParts.length - 2] = `${order}--${pathParts[pathParts.length - 2]}`;
const dirParts = [...pathParts];
dirParts.pop();
updatedFolderRenames.push({ from: originDirParts.join('/'), to: dirParts.join('/') });
} else {
files[i].updatedName = `${order}--${fileData.name}`;
}
}
}
i += 1;
}
return { files, folderRenames: updatedFolderRenames };
}
/**
* Reads a text and extracts a title from it
*
* @param {string} content The text where to extract the title from
* @param {string} engine
*/
export function extractTitle(content, engine = 'md') {
if (engine === 'md') {
let captureHeading = true;
let i = 0;
for (const line of content.split('\n')) {
if (line.startsWith('```')) {
captureHeading = !captureHeading;
}
if (captureHeading && line.startsWith('# ')) {
return { title: line.substring(2), lineNumber: i };
}
i += 1;
}
}
return { title: '', lineNumber: -1 };
}
/**
* Parses a title and extracts the relevante data for it.
* A title can contain
* - ">>" to define a parent => child relationship
* - "||" to define the order for this page
*
* @example
* Foo ||3
* Foo >> Bar ||10
*
* @param {string} inTitle
* @return {{ title: string, order: number }}
*/
export function parseTitle(inTitle) {
if (typeof inTitle !== 'string') {
throw new Error('You need to provide a string to `parseTitle`');
}
let title = inTitle;
let order = 0;
let navigationTitle = title;
if (title.includes('>>')) {
const parts = title
.split('>>')
.map(part => part.trim())
.filter(Boolean);
title = parts.join(' ');
navigationTitle = parts[parts.length - 1];
if (parts.length >= 2) {
title = `${parts[0]}: ${parts[1]}`;
const parentParts = [...parts];
parentParts.pop();
if (parts.length >= 3) {
title = `${parts[parts.length - 2]}: ${parts[parts.length - 1]}`;
}
}
}
if (title.includes('||')) {
const parts = title
.split('||')
.map(part => part.trim())
.filter(Boolean);
if (parts.length !== 2) {
throw new Error('You can use || only once in `parseTitle`');
}
navigationTitle = navigationTitle.split('||').map(part => part.trim())[0];
title = parts[0];
order = parseInt(parts[1]);
}
return {
title: navigationTitle,
order,
};
// data.parts = titleParts;
// data.title = title;
// data.eleventyNavigation = {
// key,
// title: navigationTitle,
// order,
// };
// if (parent) {
// data.eleventyNavigation.parent = parent;
// }
// return data;
}

View File

@@ -2,9 +2,10 @@ import chai from 'chai';
import { RocketCli } from '../src/RocketCli.js';
import path from 'path';
import globby from 'globby';
import fs from 'fs-extra';
import fs, { move, remove } from 'fs-extra';
import prettier from 'prettier';
import { fileURLToPath } from 'url';
import { existsSync } from 'fs';
const { expect } = chai;
@@ -91,86 +92,109 @@ export async function readOutput(
return text;
}
export function startOutputExist(cli, fileName) {
const outputDir = cli.config.outputDevDir;
return fs.existsSync(path.join(outputDir, fileName));
}
export function buildOutputExist(cli, fileName) {
const outputDir = cli.config.outputDir;
return fs.existsSync(path.join(outputDir, fileName));
}
/**
* @param {*} cli
* @param {string} fileName
* @param {readOutputOptions} options
*/
export async function readStartOutput(cli, fileName, options = {}) {
options.type = 'start';
return readOutput(cli, fileName, options);
}
/**
* @param {*} cli
* @param {string} fileName
* @param {readOutputOptions} options
*/
export async function readBuildOutput(cli, fileName, options = {}) {
options.type = 'build';
return readOutput(cli, fileName, options);
}
export async function getfixtureExpectedFiles(pathToDir) {
const cwd = path.join(fixtureDir, pathToDir);
const paths = await globby('**/*', { cwd, absolute: true, dot: true });
return paths;
}
export async function execute(cli, configFileDir) {
export async function execute(pathToConfig, { type = 'start', captureLog = false } = {}) {
let log = [];
const origLog = console.log;
if (captureLog) {
console.log = (...args) => {
log = [...log, ...args];
};
}
const configFile = path.join(fixtureDir, pathToConfig.split('/').join(path.sep));
const configFileDir = path.dirname(configFile);
const cli = new RocketCli({
argv: [type, '--config-file', configFile],
});
await cli.setup();
cli.config.outputDevDir = path.join(configFileDir, '__output-dev');
cli.config.devServer.open = false;
cli.config.devServer.port = 8080;
cli.config.watch = false;
cli.config.outputDir = path.join(configFileDir, '__output');
await fs.emptyDir(cli.config.outputDevDir);
await fs.emptyDir(cli.config.outputDir);
await cli.run();
return cli;
/**
* @param {*} cli
* @param {string} fileName
* @param {readOutputOptions} options
*/
async function readOutput2(fileName, options = {}) {
options.type = type;
return readOutput(cli, fileName, options);
}
function outputExists(fileName) {
const outputDir = type === 'build' ? cli.config.outputDir : cli.config.outputDevDir;
const filePath = path.join(outputDir, fileName);
return fs.existsSync(filePath);
}
if (captureLog) {
console.log = origLog;
}
return { log, readOutput: readOutput2, cli, outputExists };
}
export async function executeBootstrap(pathToDir) {
const configFileDir = path.join(fixtureDir, pathToDir.split('/').join(path.sep));
const cli = new RocketCli({ argv: ['bootstrap'] });
await cli.setup();
cli.config.outputDevDir = path.join(configFileDir, '__output-dev');
cli.config.devServer.open = false;
cli.config.devServer.port = 8080;
cli.config.watch = false;
cli.config.outputDir = path.join(configFileDir, '__output');
await fs.emptyDir(configFileDir);
await execute(cli, configFileDir);
return cli;
await cli.run();
return { cli };
}
export async function executeStart(pathToConfig) {
export async function executeUpgrade(pathToConfig) {
const configFile = path.join(fixtureDir, pathToConfig.split('/').join(path.sep));
const cli = new RocketCli({
argv: ['start', '--config-file', configFile],
argv: ['upgrade', '--config-file', configFile],
});
await execute(cli, path.dirname(configFile));
return cli;
}
await cli.setup();
export async function executeBuild(pathToConfig) {
const configFile = path.join(fixtureDir, pathToConfig.split('/').join(path.sep));
const cli = new RocketCli({
argv: ['build', '--config-file', configFile],
});
await execute(cli, path.dirname(configFile));
return cli;
}
export async function executeLint(pathToConfig) {
const configFile = path.join(fixtureDir, pathToConfig.split('/').join(path.sep));
const cli = new RocketCli({
argv: ['lint', '--config-file', configFile],
});
await execute(cli, path.dirname(configFile));
return cli;
// restore from backup if available - in cases the test did stop in the middle
if (cli.config._inputDirCwdRelative) {
const backupDir = path.join(cli.config._inputDirCwdRelative, '..', 'docs_backup');
if (existsSync(backupDir)) {
await remove(cli.config._inputDirCwdRelative);
await move(backupDir, cli.config._inputDirCwdRelative);
}
}
await cli.run();
return {
cli,
fileExists: fileName => {
const outputDir = cli.config._inputDirCwdRelative;
return fs.existsSync(path.join(outputDir, fileName));
},
readFile: async fileName => {
// TODO: use readOutput once it's changed to read full file paths
const filePath = path.join(cli.config._inputDirCwdRelative, fileName);
const text = await fs.promises.readFile(filePath);
return text.toString();
},
};
}
export function trimWhiteSpace(inString) {

View File

@@ -1,17 +1,11 @@
import chai from 'chai';
import chalk from 'chalk';
import {
executeBuild,
executeStart,
readBuildOutput,
readStartOutput,
setFixtureDir,
} from '@rocket/cli/test-helpers';
import { execute, setFixtureDir } from '@rocket/cli/test-helpers';
const { expect } = chai;
describe('RocketCli computedConfig', () => {
let cli;
let cleanupCli;
before(() => {
// ignore colors in tests as most CIs won't support it
@@ -20,90 +14,84 @@ describe('RocketCli computedConfig', () => {
});
afterEach(async () => {
if (cli?.cleanup) {
await cli.cleanup();
if (cleanupCli?.cleanup) {
await cleanupCli.cleanup();
}
});
it('will extract a title from markdown and set first folder as section', async () => {
cli = await executeStart('computed-config-fixtures/headlines/rocket.config.js');
it('will not create a social media image in "start"', async () => {
const { cli, readOutput } = await execute(
'computed-config-fixtures/social-images-only-build/rocket.config.js',
{
captureLog: true,
},
);
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html');
const [indexTitle, indexSection] = indexHtml.split('\n');
expect(indexTitle).to.equal('Root');
expect(indexSection).to.be.undefined;
const subHtml = await readStartOutput(cli, 'sub/index.html');
const [subTitle, subSection] = subHtml.split('\n');
expect(subTitle).to.equal('Root: Sub');
expect(subSection).to.equal('sub');
const subSubHtml = await readStartOutput(cli, 'sub/subsub/index.html');
const [subSubTitle, subSubSection] = subSubHtml.split('\n');
expect(subSubTitle).to.equal('Sub: SubSub');
expect(subSubSection).to.equal('sub');
const sub2Html = await readStartOutput(cli, 'sub2/index.html');
const [sub2Title, sub2Section] = sub2Html.split('\n');
expect(sub2Title).to.equal('Root: Sub2');
expect(sub2Section).to.equal('sub2');
const withDataHtml = await readStartOutput(cli, 'with-data/index.html');
const [withDataTitle, withDataSection] = withDataHtml.split('\n');
expect(withDataTitle).to.equal('Set via data');
expect(withDataSection).be.undefined;
});
it('will note create a social media image in "start"', async () => {
cli = await executeStart('computed-config-fixtures/social-images-only-build/rocket.config.js');
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
expect(indexHtml).to.equal('');
});
it('will create a social media image in "build"', async () => {
cli = await executeBuild('computed-config-fixtures/social-images-only-build/rocket.config.js');
const { cli, readOutput } = await execute(
'computed-config-fixtures/social-images-only-build/rocket.config.js',
{
captureLog: true,
type: 'build',
},
);
cleanupCli = cli;
const indexHtml = await readBuildOutput(cli, 'index.html', {
const indexHtml = await readOutput('index.html', {
stripToBody: true,
});
expect(indexHtml).to.equal('/_merged_assets/11ty-img/5893749-1200.png');
});
it('will create a social media image for every page', async () => {
cli = await executeStart('computed-config-fixtures/social-images/rocket.config.js');
const { cli, readOutput } = await execute(
'computed-config-fixtures/social-images/rocket.config.js',
{
captureLog: true,
},
);
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
expect(indexHtml).to.equal('/_merged_assets/11ty-img/c4c29ec7-1200.png');
const guidesHtml = await readStartOutput(cli, 'guides/index.html');
const guidesHtml = await readOutput('guides/index.html');
expect(guidesHtml).to.equal('/_merged_assets/11ty-img/c593a8cd-1200.png');
const gettingStartedHtml = await readStartOutput(
cli,
'guides/first-pages/getting-started/index.html',
);
const gettingStartedHtml = await readOutput('guides/first-pages/getting-started/index.html');
expect(gettingStartedHtml).to.equal('/_merged_assets/11ty-img/d989ab1a-1200.png');
});
it('can override the svg function globally to adjust all social media image', async () => {
cli = await executeStart('computed-config-fixtures/social-images-override/rocket.config.js');
const { cli, readOutput } = await execute(
'computed-config-fixtures/social-images-override/rocket.config.js',
{
captureLog: true,
},
);
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
expect(indexHtml).to.equal('/_merged_assets/11ty-img/d76265ed-1200.png');
const guidesHtml = await readStartOutput(cli, 'guides/index.html');
const guidesHtml = await readOutput('guides/index.html');
expect(guidesHtml).to.equal('/_merged_assets/11ty-img/d76265ed-1200.png');
const gettingStartedHtml = await readStartOutput(
cli,
'guides/first-pages/getting-started/index.html',
);
const gettingStartedHtml = await readOutput('guides/first-pages/getting-started/index.html');
expect(gettingStartedHtml).to.equal('/_merged_assets/11ty-img/d76265ed-1200.png');
});
it('will add "../" for links and image urls only within named template files', async () => {
cli = await executeStart('computed-config-fixtures/image-link/rocket.config.js');
const {
cli,
readOutput,
} = await execute('computed-config-fixtures/image-link/rocket.config.js', { captureLog: true });
cleanupCli = cli;
const namedMdContent = [
'<p>',
@@ -127,22 +115,22 @@ describe('RocketCli computedConfig', () => {
'</div>',
];
const templateHtml = await readStartOutput(cli, 'template/index.html', { formatHtml: true });
const templateHtml = await readOutput('template/index.html', { formatHtml: true });
expect(templateHtml, 'template/index.html does not match').to.equal(
namedHtmlContent.join('\n'),
);
const guidesHtml = await readStartOutput(cli, 'guides/index.html', { formatHtml: true });
const guidesHtml = await readOutput('guides/index.html', { formatHtml: true });
expect(guidesHtml, 'guides/index.html does not match').to.equal(
[...namedMdContent, ...namedHtmlContent].join('\n'),
);
const noAdjustHtml = await readStartOutput(cli, 'no-adjust/index.html');
const noAdjustHtml = await readOutput('no-adjust/index.html');
expect(noAdjustHtml, 'no-adjust/index.html does not match').to.equal(
'<p>Nothing to adjust in here</p>',
);
const rawHtml = await readStartOutput(cli, 'one-level/raw/index.html');
const rawHtml = await readOutput('one-level/raw/index.html');
expect(rawHtml, 'raw/index.html does not match').to.equal(
[
'<div>',
@@ -159,7 +147,7 @@ describe('RocketCli computedConfig', () => {
);
// for index files no '../' will be added
const indexHtml = await readStartOutput(cli, 'index.html', { formatHtml: true });
const indexHtml = await readOutput('index.html', { formatHtml: true });
expect(indexHtml, 'index.html does not match').to.equal(
[
'<p>',
@@ -188,19 +176,28 @@ describe('RocketCli computedConfig', () => {
});
it('can be configured via setupEleventyComputedConfig', async () => {
cli = await executeStart('computed-config-fixtures/setup/addPlugin.rocket.config.js');
const { cli, readOutput } = await execute(
'computed-config-fixtures/setup/addPlugin.rocket.config.js',
{
captureLog: true,
},
);
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
expect(indexHtml).to.equal('test-value');
});
it('always assigns layout-default exept for index.* files who get layout-index', async () => {
cli = await executeStart('computed-config-fixtures/layout/rocket.config.js');
const { cli, readOutput } = await execute('computed-config-fixtures/layout/rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
expect(indexHtml).to.include('<body layout="layout-index">');
const pageHtml = await readStartOutput(cli, 'page/index.html');
const pageHtml = await readOutput('page/index.html');
expect(pageHtml).to.include('<body layout="layout-default">');
});
});

View File

@@ -2,13 +2,9 @@ import chai from 'chai';
import fetch from 'node-fetch';
import chalk from 'chalk';
import {
execute,
executeBootstrap,
executeBuild,
executeLint,
executeStart,
expectThrowsAsync,
readBuildOutput,
readStartOutput,
getfixtureExpectedFiles,
setFixtureDir,
} from '@rocket/cli/test-helpers';
@@ -17,7 +13,7 @@ import fs from 'fs-extra';
const { expect } = chai;
describe('RocketCli e2e', () => {
let cli;
let cleanupCli;
before(() => {
// ignore colors in tests as most CIs won't support it
@@ -26,20 +22,24 @@ describe('RocketCli e2e', () => {
});
afterEach(async () => {
if (cli?.cleanup) {
await cli.cleanup();
if (cleanupCli?.cleanup) {
await cleanupCli.cleanup();
}
});
it('can add a unified plugin via the config', async () => {
cli = await executeStart('e2e-fixtures/unified-plugin/rocket.config.js');
const indexHtml = await readStartOutput(cli, 'index.html');
const { cli, readOutput } = await execute('e2e-fixtures/unified-plugin/rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readOutput('index.html');
expect(indexHtml).to.equal(`<p>See a 🐶</p>`);
});
describe('bootstrap command', () => {
it('can bootstrap a project', async () => {
cli = await executeBootstrap('e2e-fixtures/bootstrap/__output');
const { cli } = await executeBootstrap('e2e-fixtures/bootstrap/__output');
cleanupCli = cli;
for (const p of await getfixtureExpectedFiles('e2e-fixtures/bootstrap/expected')) {
const actual = await fs.readFile(
@@ -54,8 +54,11 @@ describe('RocketCli e2e', () => {
describe('eleventy in config', () => {
it('can modify eleventy via an elventy function in the config', async () => {
cli = await executeStart('e2e-fixtures/content/eleventy.rocket.config.js');
const indexHtml = await readStartOutput(cli, 'index.html');
const { cli, readOutput } = await execute('e2e-fixtures/content/eleventy.rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readOutput('index.html');
expect(indexHtml).to.equal(
['# BEFORE #', '<p>Content inside <code>docs/index.md</code></p>'].join('\n'),
);
@@ -63,7 +66,8 @@ describe('RocketCli e2e', () => {
it('will throw if you try to set options by returning an object', async () => {
await expectThrowsAsync(
() => executeStart('e2e-fixtures/content/eleventy-return.rocket.config.js'),
() =>
execute('e2e-fixtures/content/eleventy-return.rocket.config.js', { captureLog: true }),
{
errorMatch: /Error in your Eleventy config file.*/,
},
@@ -73,13 +77,23 @@ describe('RocketCli e2e', () => {
describe('setupDevAndBuildPlugins in config', () => {
it('can add a rollup plugin via setupDevAndBuildPlugins for build command', async () => {
cli = await executeBuild('e2e-fixtures/rollup-plugin/devbuild.rocket.config.js');
const inlineModule = await readBuildOutput(cli, 'e97af63d.js');
const { cli, readOutput } = await execute(
'e2e-fixtures/rollup-plugin/devbuild.rocket.config.js',
{
captureLog: true,
type: 'build',
},
);
cleanupCli = cli;
const inlineModule = await readOutput('e97af63d.js');
expect(inlineModule).to.equal('var a={test:"data"};console.log(a);');
});
it('can add a rollup plugin via setupDevAndBuildPlugins for start command', async () => {
cli = await executeStart('e2e-fixtures/rollup-plugin/devbuild.rocket.config.js');
const { cli } = await execute('e2e-fixtures/rollup-plugin/devbuild.rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const response = await fetch('http://localhost:8080/test-data.json');
expect(response.ok).to.be.true; // no server error
@@ -90,37 +104,56 @@ describe('RocketCli e2e', () => {
});
it('can add a rollup plugin for dev & build and modify a build only plugin via the config', async () => {
cli = await executeBuild('e2e-fixtures/rollup-plugin/devbuild-build.rocket.config.js');
const inlineModule = await readBuildOutput(cli, 'e97af63d.js');
const { cli, readOutput } = await execute(
'e2e-fixtures/rollup-plugin/devbuild-build.rocket.config.js',
{
captureLog: true,
type: 'build',
},
);
cleanupCli = cli;
const inlineModule = await readOutput('e97af63d.js');
expect(inlineModule).to.equal('var a={test:"data"};console.log(a);');
});
it('can adjust the inputDir', async () => {
cli = await executeStart('e2e-fixtures/change-input-dir/rocket.config.js');
const { cli, readOutput } = await execute('e2e-fixtures/change-input-dir/rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
expect(indexHtml).to.equal('<p>Markdown in <code>docs/page/index.md</code></p>');
});
it('can access main rocket config values via {{rocketConfig.value}}', async () => {
cli = await executeStart('e2e-fixtures/rocket-config-in-template/rocket.config.js');
const { cli, readOutput } = await execute(
'e2e-fixtures/rocket-config-in-template/rocket.config.js',
{
captureLog: true,
},
);
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
expect(indexHtml).to.equal(
'<p>You can show Rocket config data like rocketConfig.absoluteBaseUrl = <a href="http://test-domain.com/">http://test-domain.com/</a></p>',
);
});
it('can add a pathPrefix that will not influence the start command', async () => {
cli = await executeStart('e2e-fixtures/content/pathPrefix.rocket.config.js');
const { cli, readOutput } = await execute('e2e-fixtures/content/pathPrefix.rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const linkHtml = await readStartOutput(cli, 'link/index.html');
const linkHtml = await readOutput('link/index.html');
expect(linkHtml).to.equal(
['<p><a href="../">home</a></p>', '<p><a href="/">absolute home</a></p>'].join('\n'),
);
const assetHtml = await readStartOutput(cli, 'use-assets/index.html');
const assetHtml = await readOutput('use-assets/index.html');
expect(assetHtml).to.equal('<link rel="stylesheet" href="/_merged_assets/some.css">');
const imageHtml = await readStartOutput(cli, 'image/index.html', { replaceImageHashes: true });
const imageHtml = await readOutput('image/index.html', { replaceImageHashes: true });
expect(imageHtml).to.equal(
[
'<p>',
@@ -147,9 +180,13 @@ describe('RocketCli e2e', () => {
});
it('can add a pathPrefix that will be used in the build command', async () => {
cli = await executeBuild('e2e-fixtures/content/pathPrefix.rocket.config.js');
const { cli, readOutput } = await execute('e2e-fixtures/content/pathPrefix.rocket.config.js', {
captureLog: true,
type: 'build',
});
cleanupCli = cli;
const linkHtml = await readBuildOutput(cli, 'link/index.html', {
const linkHtml = await readOutput('link/index.html', {
stripToBody: true,
});
expect(linkHtml).to.equal(
@@ -157,11 +194,11 @@ describe('RocketCli e2e', () => {
'\n',
),
);
const assetHtml = await readBuildOutput(cli, 'use-assets/index.html');
const assetHtml = await readOutput('use-assets/index.html');
expect(assetHtml).to.equal(
'<html><head><link rel="stylesheet" href="../41297ffa.css">\n\n</head><body>\n\n</body></html>',
);
let imageHtml = await readBuildOutput(cli, 'image/index.html');
let imageHtml = await readOutput('image/index.html');
imageHtml = imageHtml.replace(/\.\.\/([a-z0-9]+)\./g, '../__HASH__.');
expect(imageHtml).to.equal(
[
@@ -184,15 +221,22 @@ describe('RocketCli e2e', () => {
});
it('smoke test for link checking', async () => {
await expectThrowsAsync(() => executeLint('e2e-fixtures/lint-links/rocket.config.js'), {
errorMatch: /Found 1 missing reference targets/,
});
await expectThrowsAsync(
() => execute('e2e-fixtures/lint-links/rocket.config.js', { captureLog: true, type: 'lint' }),
{
errorMatch: /Found 1 missing reference targets/,
},
);
});
it('can completely take over the rollup config', async () => {
cli = await executeBuild('e2e-fixtures/rollup-override/rocket.config.js');
const { cli, readOutput } = await execute('e2e-fixtures/rollup-override/rocket.config.js', {
captureLog: true,
type: 'build',
});
cleanupCli = cli;
const indexHtml = await readBuildOutput(cli, 'index.html', {
const indexHtml = await readOutput('index.html', {
stripToBody: true,
formatHtml: true,
});
@@ -207,4 +251,33 @@ describe('RocketCli e2e', () => {
].join('\n'),
);
});
describe('can adjust the eleventy config while having access to the rocketConfig', () => {
it('testing start', async () => {
const { cli, readOutput } = await execute(
'e2e-fixtures/adjust-eleventy-config/rocket.config.js',
{
captureLog: true,
},
);
cleanupCli = cli;
const indexHtml = await readOutput('index.html');
expect(indexHtml).to.equal('<p><a href="start:/path/to/page/">link</a></p>');
});
it('testing build', async () => {
const { cli, readOutput } = await execute(
'e2e-fixtures/adjust-eleventy-config/rocket.config.js',
{
captureLog: true,
type: 'build',
},
);
cleanupCli = cli;
const indexBuildHtml = await readOutput('index.html', {
stripToBody: true,
});
expect(indexBuildHtml).to.equal('<p><a href="build:/path/to/page/">link</a></p>');
});
});
});

View File

@@ -1,11 +1,11 @@
import chai from 'chai';
import chalk from 'chalk';
import { executeStart, readStartOutput, setFixtureDir } from '@rocket/cli/test-helpers';
import { execute, setFixtureDir } from '@rocket/cli/test-helpers';
const { expect } = chai;
describe('RocketCli images', () => {
let cli;
let cleanupCli;
before(() => {
// ignore colors in tests as most CIs won't support it
@@ -14,15 +14,18 @@ describe('RocketCli images', () => {
});
afterEach(async () => {
if (cli?.cleanup) {
await cli.cleanup();
if (cleanupCli?.cleanup) {
await cleanupCli.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', {
const { cli, readOutput } = await execute('e2e-fixtures/images/rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readOutput('index.html', {
formatHtml: true,
replaceImageHashes: true,
});
@@ -57,7 +60,7 @@ describe('RocketCli images', () => {
].join('\n'),
);
const keepSvgHtml = await readStartOutput(cli, 'ignores/index.html', {
const keepSvgHtml = await readOutput('ignores/index.html', {
formatHtml: true,
replaceImageHashes: true,
});
@@ -102,7 +105,7 @@ describe('RocketCli images', () => {
].join('\n'),
);
const tableHtml = await readStartOutput(cli, 'table/index.html', {
const tableHtml = await readOutput('table/index.html', {
formatHtml: true,
replaceImageHashes: true,
});
@@ -150,8 +153,12 @@ describe('RocketCli images', () => {
});
it('can configure more patterns to ignore', async () => {
cli = await executeStart('e2e-fixtures/images/ignore-more.rocket.config.js');
const keepSvgHtml = await readStartOutput(cli, 'ignores/index.html', {
const { cli, readOutput } = await execute(
'e2e-fixtures/images/ignore-more.rocket.config.js',
{ captureLog: true },
);
cleanupCli = cli;
const keepSvgHtml = await readOutput('ignores/index.html', {
formatHtml: true,
replaceImageHashes: true,
});
@@ -178,16 +185,17 @@ describe('RocketCli images', () => {
});
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', {
const { cli, readOutput } = await execute('e2e-fixtures/images/rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readOutput('two-images/index.html', {
formatHtml: true,
replaceImageHashes: true,
});
expect(indexHtml).to.equal(
[
'<h2 id="one">',
' <a aria-hidden="true" tabindex="-1" href="#one"><span class="icon icon-link"></span></a>one',
'</h2>',
'<p>one</p>',
'<p>',
' <picture>',
' <source',
@@ -211,9 +219,7 @@ describe('RocketCli images', () => {
' />',
' </picture>',
'</p>',
'<h2 id="two">',
' <a aria-hidden="true" tabindex="-1" href="#two"><span class="icon icon-link"></span></a>two',
'</h2>',
'<p>two</p>',
'<p>',
' <picture>',
' <source',
@@ -242,8 +248,11 @@ describe('RocketCli images', () => {
});
it('can configure those responsive images', async () => {
cli = await executeStart('e2e-fixtures/images/small.rocket.config.js');
const indexHtml = await readStartOutput(cli, 'index.html', {
const { cli, readOutput } = await execute('e2e-fixtures/images/small.rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readOutput('index.html', {
formatHtml: true,
replaceImageHashes: true,
});
@@ -280,8 +289,11 @@ describe('RocketCli images', () => {
});
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', {
const { cli, readOutput } = await execute('e2e-fixtures/images/small.rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readOutput('no-title/index.html', {
formatHtml: true,
replaceImageHashes: true,
});
@@ -315,8 +327,12 @@ describe('RocketCli images', () => {
});
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', {
const {
cli,
readOutput,
} = await execute('e2e-fixtures/images/single-format.rocket.config.js', { captureLog: true });
cleanupCli = cli;
const indexHtml = await readOutput('no-title/index.html', {
formatHtml: true,
replaceImageHashes: true,
});

View File

@@ -0,0 +1,77 @@
import chai from 'chai';
import chalk from 'chalk';
import { execute, setFixtureDir } from '@rocket/cli/test-helpers';
const { expect } = chai;
describe('RocketCli Menu', () => {
let cleanupCli;
before(() => {
// ignore colors in tests as most CIs won't support it
chalk.level = 0;
setFixtureDir(import.meta.url);
});
afterEach(async () => {
if (cleanupCli?.cleanup) {
await cleanupCli.cleanup();
}
});
it('will render a menu', async () => {
const { cli, readOutput } = await execute('e2e-fixtures/menu/rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readOutput('index.html', {
formatHtml: true,
});
expect(indexHtml).to.equal(
[
'<html>',
' <head> </head>',
' <body>',
' <web-menu name="site">',
' <nav aria-label="site">',
' <a href="/components/">Components</a>',
' <a href="/getting-started/">Getting Started</a>',
' <a href="/blog/">Blog</a>',
' </nav>',
' </web-menu>',
' <h1 id="menu-page">',
' <a aria-hidden="true" tabindex="-1" href="#menu-page"><span class="icon icon-link"></span></a',
' >Menu Page',
' </h1>',
' </body>',
'</html>',
].join('\n'),
);
const accordion = await readOutput('components/content/accordion/index.html', {
formatHtml: true,
});
expect(accordion).to.equal(
[
'<html>',
' <head>',
' <meta name="menu:order" content="10" />',
' </head>',
' <body>',
' <web-menu name="site">',
' <nav aria-label="site">',
' <a href="/components/">Components</a>',
' <a href="/getting-started/">Getting Started</a>',
' <a href="/blog/">Blog</a>',
' </nav>',
' </web-menu>',
' <h1 id="accordion">',
' <a aria-hidden="true" tabindex="-1" href="#accordion"><span class="icon icon-link"></span></a',
' >Accordion',
' </h1>',
' </body>',
'</html>',
].join('\n'),
);
});
});

View File

@@ -1,16 +1,11 @@
import chai from 'chai';
import chalk from 'chalk';
import {
executeStart,
readStartOutput,
trimWhiteSpace,
setFixtureDir,
} from '@rocket/cli/test-helpers';
import { execute, trimWhiteSpace, setFixtureDir } from '@rocket/cli/test-helpers';
const { expect } = chai;
describe('RocketCli mergeTemplates', () => {
let cli;
let cleanupCli;
before(() => {
// ignore colors in tests as most CIs won't support it
@@ -19,15 +14,18 @@ describe('RocketCli mergeTemplates', () => {
});
afterEach(async () => {
if (cli?.cleanup) {
await cli.cleanup();
if (cleanupCli?.cleanup) {
await cleanupCli.cleanup();
}
});
it('merges it in the defined order', async () => {
cli = await executeStart('merge-templates-fixtures/order/rocket.config.js');
const { cli, readOutput } = await execute('merge-templates-fixtures/order/rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
expect(trimWhiteSpace(indexHtml)).to.equal(
[
'<p>30-first</p>',
@@ -40,9 +38,13 @@ describe('RocketCli mergeTemplates', () => {
});
it('presets can overwrite in order', async () => {
cli = await executeStart('merge-templates-fixtures/overwrite/rocket.config.js');
const { cli, readOutput } = await execute(
'merge-templates-fixtures/overwrite/rocket.config.js',
{ captureLog: true },
);
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
expect(trimWhiteSpace(indexHtml)).to.equal(
['<p>overwritten second</p>', '<p>third</p>', '<p>overwritten first to be last</p>'].join(
'\n',
@@ -51,9 +53,12 @@ describe('RocketCli mergeTemplates', () => {
});
it('presets can add inbetween', async () => {
cli = await executeStart('merge-templates-fixtures/add/rocket.config.js');
const { cli, readOutput } = await execute('merge-templates-fixtures/add/rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
expect(trimWhiteSpace(indexHtml)).to.equal(
[
'<p>first</p>',

View File

@@ -1,11 +1,11 @@
import chai from 'chai';
import chalk from 'chalk';
import { executeStart, readStartOutput, setFixtureDir } from '@rocket/cli/test-helpers';
import { execute, setFixtureDir } from '@rocket/cli/test-helpers';
const { expect } = chai;
describe('RocketCli preset', () => {
let cli;
let cleanupCli;
before(() => {
// ignore colors in tests as most CIs won't support it
@@ -14,21 +14,24 @@ describe('RocketCli preset', () => {
});
afterEach(async () => {
if (cli?.cleanup) {
await cli.cleanup();
if (cleanupCli?.cleanup) {
await cleanupCli.cleanup();
}
});
it('offers a default layout (with head, header, content, footer, bottom) and raw layout', async () => {
cli = await executeStart('preset-fixtures/default/rocket.config.js');
const { cli, readOutput } = await execute('preset-fixtures/default/rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const rawHtml = await readStartOutput(cli, 'raw/index.html');
const rawHtml = await readOutput('raw/index.html');
expect(rawHtml).to.equal('<p>Just raw</p>');
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
expect(indexHtml).to.include('<body layout="layout-index">');
const pageHtml = await readStartOutput(cli, 'page/index.html', {
const pageHtml = await readOutput('page/index.html', {
stripScripts: true,
formatHtml: true,
});
@@ -69,7 +72,7 @@ describe('RocketCli preset', () => {
' <div class="content-area">',
' <a class="logo-link" href="/">',
' <img src="/_merged_assets/logo.svg" alt="" />',
' <span class="sr-only">Rocket</span>',
' <span>Rocket</span>',
' </a>',
' </div>',
' </header>',
@@ -86,12 +89,6 @@ describe('RocketCli preset', () => {
' </div>',
'',
' <footer id="main-footer"></footer>',
'',
' <script',
' type="module"',
' inject-service-worker=""',
' src="/_merged_assets/scripts/registerServiceWorker.js"',
' ></script>',
' </body>',
'</html>',
].join('\n'),
@@ -99,16 +96,22 @@ describe('RocketCli preset', () => {
});
it('allows to add content to the head without overriding', async () => {
cli = await executeStart('preset-fixtures/add-to-head/rocket.config.js');
const { cli, readOutput } = await execute('preset-fixtures/add-to-head/rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html');
const indexHtml = await readOutput('index.html');
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 { cli, readOutput } = await execute('preset-fixtures/use-preset/rocket.config.js', {
captureLog: true,
});
cleanupCli = cli;
const indexHtml = await readStartOutput(cli, 'index.html', {
const indexHtml = await readOutput('index.html', {
formatHtml: true,
replaceImageHashes: true,
});

View File

@@ -1,6 +1,6 @@
import chai from 'chai';
import chalk from 'chalk';
import { executeBuild, readStartOutput, setFixtureDir } from '@rocket/cli/test-helpers';
import { execute, setFixtureDir } from '@rocket/cli/test-helpers';
const { expect } = chai;
@@ -17,7 +17,7 @@ function getServiceWorkerUrl(text) {
}
describe('RocketCli e2e', () => {
let cli;
let cleanupCli;
before(() => {
// ignore colors in tests as most CIs won't support it
@@ -26,20 +26,28 @@ describe('RocketCli e2e', () => {
});
afterEach(async () => {
if (cli?.cleanup) {
await cli.cleanup();
if (cleanupCli?.cleanup) {
await cleanupCli.cleanup();
}
});
it('will add a script to inject the service worker', async () => {
cli = await executeBuild('e2e-fixtures/service-worker/rocket.config.js');
const indexHtml = await readStartOutput(cli, 'index.html');
const { cli, readOutput } = await execute('e2e-fixtures/service-worker/rocket.config.js', {
captureLog: true,
type: 'build',
});
cleanupCli = cli;
// we check the start output here as in the rollup build version it's hard to find
const indexHtml = await readOutput('../__output-dev/index.html');
const indexInject = getInjectServiceWorker(indexHtml);
expect(indexInject).to.equal(
'<script type="module" inject-service-worker="" src="/_merged_assets/scripts/registerServiceWorker.js"></script>',
);
expect(getServiceWorkerUrl(indexHtml)).to.equal('/service-worker.js');
const subHtml = await readStartOutput(cli, 'sub/index.html');
// we check the start output here as in the rollup build version it's hard to find
const subHtml = await readOutput('../__output-dev/sub/index.html');
const subInject = getInjectServiceWorker(subHtml);
expect(subInject).to.equal(
'<script type="module" inject-service-worker="" src="/_merged_assets/scripts/registerServiceWorker.js"></script>',
@@ -49,14 +57,21 @@ describe('RocketCli e2e', () => {
// TODO: find a way to run these test either by forcing pathPrefix in start or skipping asset gathering for build or ...
it.skip('will add a script to inject the service worker', async () => {
cli = await executeBuild('e2e-fixtures/service-worker/pathPrefix.rocket.config.js');
const indexHtml = await readStartOutput(cli, 'index.html');
const { cli, readOutput } = await execute(
'e2e-fixtures/service-worker/pathPrefix.rocket.config.js',
{
captureLog: true,
type: 'build',
},
);
cleanupCli = cli;
const indexHtml = await readOutput('index.html');
const indexInject = getInjectServiceWorker(indexHtml);
expect(indexInject).to.equal(
'<script type="module" inject-service-worker="" src="/my-prefix-folder/_merged_assets/scripts/registerServiceWorker.js"></script>',
);
expect(getServiceWorkerUrl(indexHtml)).to.equal('/my-prefix-folder/service-worker.js');
const subHtml = await readStartOutput(cli, 'sub/index.html');
const subHtml = await readOutput('sub/index.html');
const subInject = getInjectServiceWorker(subHtml);
expect(subInject).to.equal(
'<script type="module" inject-service-worker="" src="/my-prefix-folder/_merged_assets/scripts/registerServiceWorker.js"></script>',

View File

@@ -0,0 +1,57 @@
import chai from 'chai';
import chalk from 'chalk';
import path from 'path';
import { executeUpgrade, setFixtureDir } from '@rocket/cli/test-helpers';
import { move, remove } from 'fs-extra';
import { existsSync } from 'fs';
const { expect } = chai;
describe('Upgrade System', () => {
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();
}
if (cli?.config._inputDirCwdRelative) {
const backupDir = path.join(cli.config._inputDirCwdRelative, '..', 'docs_backup');
if (existsSync(backupDir)) {
await remove(cli.config._inputDirCwdRelative);
await move(backupDir, cli.config._inputDirCwdRelative);
}
}
});
it('2021-09-menu', async () => {
const run = await executeUpgrade('fixtures-upgrade/2021-09-menu/rocket.config.js');
cli = run.cli;
expect(run.fileExists('index.md')).to.be.true;
expect(run.fileExists('31--components/index.md')).to.be.true;
expect(await run.readFile('31--components/index.md')).to.equal(
[
'---',
'menu:',
' linkText: Components',
'---',
'',
'# Component Directory',
'',
'Here you get started.',
'',
].join('\n'),
);
expect(run.fileExists('31--components/10--content/20--accordion/overview.md')).to.be.false;
expect(run.fileExists('31--components/10--content/20--accordion/10--overview.md')).to.be.true;
expect(await run.readFile('31--components/10--content/20--accordion/10--overview.md')).to.equal(
'# Overview\n',
);
});
});

View File

@@ -1,16 +1,11 @@
import chai from 'chai';
import chalk from 'chalk';
import {
executeStart,
readStartOutput,
setFixtureDir,
startOutputExist,
} from '@rocket/cli/test-helpers';
import { execute, setFixtureDir } from '@rocket/cli/test-helpers';
const { expect } = chai;
describe('RocketCli use cases', () => {
let cli;
let cleanupCli;
before(() => {
// ignore colors in tests as most CIs won't support it
@@ -19,18 +14,22 @@ describe('RocketCli use cases', () => {
});
afterEach(async () => {
if (cli?.cleanup) {
await cli.cleanup();
if (cleanupCli?.cleanup) {
await cleanupCli.cleanup();
}
});
it('supports dynamic imports', async () => {
cli = await executeStart('use-cases/dynamic-imports/rocket.config.js');
const {
cli,
readOutput,
outputExists,
} = await execute('use-cases/dynamic-imports/rocket.config.js', { captureLog: true });
cleanupCli = cli;
expect(startOutputExist(cli, 'sub/assets/myData.js'), 'static files did not get copied').to.be
.true;
expect(outputExists('sub/assets/myData.js'), 'static files did not get copied').to.be.true;
const aboutHtml = await readStartOutput(cli, 'about/index.html', { formatHtml: true });
const aboutHtml = await readOutput('about/index.html', { formatHtml: true });
expect(aboutHtml).to.equal(
[
'<p><code>about.md</code></p>',
@@ -38,7 +37,7 @@ describe('RocketCli use cases', () => {
].join('\n'),
);
const subHtml = await readStartOutput(cli, 'sub/index.html', { formatHtml: true });
const subHtml = await readOutput('sub/index.html', { formatHtml: true });
expect(subHtml).to.equal(
[
'<p><code>sub/index.md</code></p>',
@@ -46,7 +45,7 @@ describe('RocketCli use cases', () => {
].join('\n'),
);
const subDetailsHtml = await readStartOutput(cli, 'sub/details/index.html', {
const subDetailsHtml = await readOutput('sub/details/index.html', {
formatHtml: true,
});
expect(subDetailsHtml).to.equal(
@@ -56,7 +55,7 @@ describe('RocketCli use cases', () => {
].join('\n'),
);
const indexHtml = await readStartOutput(cli, 'index.html', { formatHtml: true });
const indexHtml = await readOutput('index.html', { formatHtml: true });
expect(indexHtml).to.equal(
[
'<p><code>index.md</code></p>',

View File

@@ -1,3 +1,4 @@
import remark2rehype from 'remark-rehype';
import { adjustPluginOptions } from 'plugins-manager';
function image(h, node) {
@@ -10,7 +11,7 @@ function image(h, node) {
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
const config = {
setupUnifiedPlugins: [
adjustPluginOptions('remark2rehype', {
adjustPluginOptions(remark2rehype, {
handlers: {
image,
},

View File

@@ -1,8 +1,16 @@
import { addPlugin } from 'plugins-manager';
class Test {
static dataName = 'test';
execute() {
return 'test-value';
}
}
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
const config = {
setupEleventyComputedConfig: [addPlugin({ name: 'test', plugin: () => 'test-value' })],
setupEleventyComputedConfig: [addPlugin(Test)],
};
export default config;

View File

@@ -1,4 +1,5 @@
import { adjustPluginOptions } from 'plugins-manager';
import { SocialMediaImagePlugin } from '@rocket/cli';
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
const config = {
@@ -6,7 +7,7 @@ const config = {
createSocialMediaImages: true,
},
setupEleventyComputedConfig: [
adjustPluginOptions('socialMediaImage', {
adjustPluginOptions(SocialMediaImagePlugin, {
createSocialImageSvg: async () => {
return `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 630">

View File

@@ -0,0 +1,5 @@
---
layout: layout-raw
---
<a href="{{ '/path/to/page/' | conditional-resolve }}">link</a>

View File

@@ -0,0 +1,15 @@
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
const config = {
eleventy: (config, rocketConfig) => {
config.addFilter('conditional-resolve', value => {
if (rocketConfig.command === 'build') {
return `build:${value}`;
}
if (rocketConfig.command === 'start') {
return `start:${value}`;
}
});
},
};
export default config;

View File

@@ -2,10 +2,10 @@
layout: layout-raw
---
## one
one
![one](./_assets/my-image.jpg)
## two
two
![two](./_assets/my-image.jpg)

View File

@@ -0,0 +1 @@
# Components

View File

@@ -0,0 +1 @@
# Getting Started

View File

@@ -0,0 +1 @@
# Blog

View File

@@ -0,0 +1,11 @@
<html>
<head>
{% if menu.order %}
<meta name="menu:order" content="{{ menu.order }}" />
{% endif %}
</head>
<body>
<web-menu name="site"></web-menu>
{{ content | safe }}
</body>
</html>

View File

@@ -0,0 +1 @@
# Menu Page

View File

@@ -0,0 +1 @@
export default {};

View File

@@ -1,11 +1,14 @@
// @ts-no-check
import json from '@rollup/plugin-json';
import { rollupPluginHTML } from '@web/rollup-plugin-html';
import { addPlugin, adjustPluginOptions } from 'plugins-manager';
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
const config = {
setupDevAndBuildPlugins: [addPlugin({ name: 'json', plugin: json, location: 'top' })],
setupBuildPlugins: [adjustPluginOptions('html', { absoluteBaseUrl: 'https://test-me.com' })],
setupDevAndBuildPlugins: [addPlugin(json, {}, { location: 'top' })],
setupBuildPlugins: [
adjustPluginOptions(rollupPluginHTML, { absoluteBaseUrl: 'https://test-me.com' }),
],
};
export default config;

View File

@@ -1,10 +1,9 @@
// @ts-no-check
import json from '@rollup/plugin-json';
import { addPlugin } from 'plugins-manager';
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
const config = {
setupDevAndBuildPlugins: [addPlugin({ name: 'json', plugin: json, location: 'top' })],
setupDevAndBuildPlugins: [addPlugin(json, {}, { location: 'top' })],
devServer: {
mimeTypes: {
// serve all json files as js

View File

@@ -1,10 +1,11 @@
// @ts-check
import emoji from 'remark-emoji';
import { addPlugin } from 'plugins-manager';
import markdown from 'remark-parse';
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
const config = {
setupUnifiedPlugins: [addPlugin({ location: 'markdown', name: 'emoji', plugin: emoji })],
setupUnifiedPlugins: [addPlugin(emoji, {}, { location: markdown })],
};
export default config;

View File

@@ -0,0 +1,11 @@
<html>
<head>
{% if menuOrder %}
<meta name="menu:order" content="{{ menuOrder }}"/>
{% endif %}
</head>
<body>
<web-menu name="site"></web-menu>
{{ content | safe }}
</body>
</html>

View File

@@ -0,0 +1 @@
# Components >> Content >> Accordion >> Api || 20

View File

@@ -0,0 +1 @@
# Components >> Content >> Accordion || 20

View File

@@ -0,0 +1 @@
# Components >> Content >> Accordion >> Overview || 10

View File

@@ -0,0 +1 @@
# Components >> Content || 10

View File

@@ -0,0 +1 @@
# Components >> Content >> Tabs || 10

View File

@@ -0,0 +1,8 @@
---
title: Component Directory
eleventyNavigation:
key: Components
order: 31
---
Here you get started.

View File

@@ -0,0 +1,3 @@
---
title: Rocket
---

View File

@@ -0,0 +1,3 @@
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */
const config = {};
export default config;

View File

@@ -1,89 +0,0 @@
import chai from 'chai';
import { RocketCli } from '../src/RocketCli.js';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs-extra';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const { expect } = chai;
/**
* @param {function} method
* @param {string} errorMessage
*/
export async function expectThrowsAsync(method, { errorMatch, errorMessage } = {}) {
let error = null;
try {
await method();
} catch (err) {
error = err;
}
expect(error).to.be.an('Error', 'No error was thrown');
if (errorMatch) {
expect(error.message).to.match(errorMatch);
}
if (errorMessage) {
expect(error.message).to.equal(errorMessage);
}
}
export async function readOutput(
cli,
fileName,
{ stripToBody = false, stripStartEndWhitespace = true, type = 'build' } = {},
) {
const outputDir = type === 'build' ? cli.config.outputDir : cli.config.outputDevDir;
let text = await fs.promises.readFile(path.join(outputDir, fileName));
text = text.toString();
if (stripToBody) {
const bodyOpenTagEnd = text.indexOf('>', text.indexOf('<body') + 1) + 1;
const bodyCloseTagStart = text.indexOf('</body>');
text = text.substring(bodyOpenTagEnd, bodyCloseTagStart);
}
if (stripStartEndWhitespace) {
text = text.trim();
}
return text;
}
export async function readStartOutput(cli, fileName, options = {}) {
options.type = 'start';
return readOutput(cli, fileName, options);
}
export async function execute(cli, configFileDir) {
await cli.setup();
cli.config.outputDevDir = path.join(configFileDir, '__output-dev');
cli.config.devServer.open = false;
cli.config.watch = false;
cli.config.outputDir = path.join(configFileDir, '__output');
await cli.run();
return cli;
}
export async function executeStart(pathToConfig) {
const configFile = path.join(__dirname, pathToConfig.split('/').join(path.sep));
const cli = new RocketCli({
argv: ['start', '--config-file', configFile],
});
await execute(cli, path.dirname(configFile));
return cli;
}
export async function executeLint(pathToConfig) {
const configFile = path.join(__dirname, pathToConfig.split('/').join(path.sep));
const cli = new RocketCli({
argv: ['lint', '--config-file', configFile],
});
await execute(cli, path.dirname(configFile));
return cli;
}
export function trimWhiteSpace(inString) {
return inString
.split('\n')
.map(line => line.trim())
.filter(line => line)
.join('\n');
}

View File

@@ -14,19 +14,32 @@ function cleanup(config) {
delete configNoPaths.eleventy;
delete configNoPaths.outputDevDir;
delete configNoPaths.imagePresets.responsive.ignore;
delete configNoPaths.presets;
delete configNoPaths.setupCliPlugins;
return configNoPaths;
}
const plugins = [
{ commands: ['start'] },
{ commands: ['build'] },
{ commands: ['start', 'build', 'lint'] }, // lint
{ commands: ['upgrade'] },
{ commands: ['start', 'build', 'lint'] }, // web-menu
];
describe('normalizeConfig', () => {
it('makes sure essential settings are there', async () => {
const configFile = path.join(__dirname, 'fixtures', 'empty', 'rocket.config.js');
const config = await normalizeConfig({ configFile });
// testing pathes is always a little more complicted 😅
// testing pathes is always a little more complicated 😅
expect(config._inputDirCwdRelative).to.match(/empty\/docs$/);
expect(config._presetPaths[0]).to.match(/cli\/preset$/);
expect(config._presetPaths[1]).to.match(/empty\/docs$/);
expect(config._presetPaths[1]).to.match(/web-menu\/preset$/);
expect(config._presetPaths[2]).to.match(/empty\/docs$/);
expect(config.outputDevDir).to.match(/_site-dev$/);
expect(config.presets.length).to.equal(1);
expect(config.setupCliPlugins.length).to.equal(1);
expect(cleanup(config)).to.deep.equal({
__before11tyFunctions: [],
@@ -41,14 +54,9 @@ describe('normalizeConfig', () => {
setupDevPlugins: [],
setupEleventyPlugins: [],
setupEleventyComputedConfig: [],
setupCliPlugins: [],
presets: [],
setupMenus: [],
serviceWorkerName: 'service-worker.js',
plugins: [
{ commands: ['start'] },
{ commands: ['build'] },
{ commands: ['start', 'build', 'lint'] },
],
plugins,
imagePresets: {
responsive: {
formats: ['avif', 'jpeg'],
@@ -84,9 +92,8 @@ describe('normalizeConfig', () => {
setupDevAndBuildPlugins: [],
setupDevPlugins: [],
setupEleventyPlugins: [],
setupCliPlugins: [],
setupEleventyComputedConfig: [],
presets: [],
setupMenus: [],
imagePresets: {
responsive: {
formats: ['avif', 'jpeg'],
@@ -95,11 +102,7 @@ describe('normalizeConfig', () => {
},
},
serviceWorkerName: 'service-worker.js',
plugins: [
{ commands: ['start'] },
{ commands: ['build'] },
{ commands: ['start', 'build', 'lint'] },
],
plugins,
inputDir: 'docs',
outputDir: '_site',
});
@@ -125,9 +128,8 @@ describe('normalizeConfig', () => {
setupDevAndBuildPlugins: [],
setupDevPlugins: [],
setupEleventyPlugins: [],
setupCliPlugins: [],
setupEleventyComputedConfig: [],
presets: [],
setupMenus: [],
imagePresets: {
responsive: {
formats: ['avif', 'jpeg'],
@@ -136,11 +138,7 @@ describe('normalizeConfig', () => {
},
},
serviceWorkerName: 'service-worker.js',
plugins: [
{ commands: ['start'] },
{ commands: ['build'] },
{ commands: ['start', 'build', 'lint'] },
],
plugins,
inputDir: 'docs',
outputDir: '_site',
});
@@ -169,9 +167,8 @@ describe('normalizeConfig', () => {
setupDevAndBuildPlugins: [],
setupDevPlugins: [],
setupEleventyPlugins: [],
setupCliPlugins: [],
setupEleventyComputedConfig: [],
presets: [],
setupMenus: [],
imagePresets: {
responsive: {
formats: ['avif', 'jpeg'],
@@ -180,11 +177,7 @@ describe('normalizeConfig', () => {
},
},
serviceWorkerName: 'service-worker.js',
plugins: [
{ commands: ['start'] },
{ commands: ['build'] },
{ commands: ['start', 'build', 'lint'] },
],
plugins,
inputDir: 'docs',
outputDir: '_site',
});

22
packages/cli/types/upgrade.d.ts vendored Normal file
View File

@@ -0,0 +1,22 @@
export interface UpgradeFile {
path: string;
relPath: string;
name: string;
extName: string;
updatedContent?: string;
updatedPath?: string;
updatedRelPath?: string;
updatedName?: string;
}
export interface FolderRename {
from: string;
to: string;
fromAbsolute?: string;
toAbsolute?: string;
}
export interface upgrade {
files: UpgradeFile[];
folderRenames: FolderRename[];
}

View File

@@ -1,5 +1,16 @@
# @rocket/eleventy-plugin-mdjs-unified
## 0.6.0
### Minor Changes
- 70bb7a1: BREAKING CHANGE: Updating to latest version of `@mdjs/core` which requires the latest version of `plugins-manager`
### Patch Changes
- Updated dependencies [70bb7a1]
- @mdjs/core@0.9.0
## 0.5.2
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@rocket/eleventy-plugin-mdjs-unified",
"version": "0.5.2",
"version": "0.6.0",
"publishConfig": {
"access": "public"
},
@@ -31,7 +31,7 @@
"mdjs"
],
"dependencies": {
"@mdjs/core": "^0.8.2",
"@mdjs/core": "^0.9.0",
"es-module-lexer": "^0.3.26",
"unist-util-visit": "^2.0.3"
},

View File

@@ -5,6 +5,7 @@ const fs = require('fs');
const { mdjsProcess } = require('@mdjs/core');
const visit = require('unist-util-visit');
const { init, parse } = require('es-module-lexer');
const markdown = require('remark-parse');
// @ts-ignore
const { parseTitle } = require('@rocket/core/title');
@@ -45,12 +46,12 @@ function cleanupTitleHeadline() {
* @param {MdjsProcessPlugin[]} plugins
*/
function addCleanupTitleHeadline(plugins) {
if (plugins.findIndex(plugin => plugin.name === 'cleanupTitleHeadline') === -1) {
if (plugins.findIndex(pluginObj => pluginObj.plugin === cleanupTitleHeadline) === -1) {
// add plugins right after markdown
const markdownPluginIndex = plugins.findIndex(plugin => plugin.name === 'markdown');
const markdownPluginIndex = plugins.findIndex(pluginObj => pluginObj.plugin === markdown);
plugins.splice(markdownPluginIndex + 1, 0, {
name: 'cleanupTitleHeadline',
plugin: cleanupTitleHeadline,
options: {},
});
}
return plugins;

View File

@@ -1,8 +1,9 @@
const htmlHeading = require('rehype-autolink-headings');
const pluginMdjs = require('../../../index.js');
function addClassAnchorToHtmlHeading(plugins) {
return plugins.map(pluginObj => {
if (pluginObj.name === 'htmlHeading') {
if (pluginObj.plugin === htmlHeading) {
return {
...pluginObj,
options: {

View File

@@ -1,5 +1,28 @@
# @rocket/launch
## 0.6.0
### Minor Changes
- 70bb7a1: BREAKING CHANGE: Update to latest plugins manager to get type safe options
There is no longer a name string as a key for a plugin. It is identified by it's function/class. You will need to adjust your code if you are adding or adjusting plugins.
```diff
- addPlugin({ name: 'my-plugin', plugin: myPlugin, options: { myFlag: true }, location: 'top' });
+ addPlugin(myPlugin, { myFlag: true }, { location: 'top' });
- adjustPluginOptions('my-plugin', { myFlag: true });
+ adjustPluginOptions(myPlugin, { myFlag: true });
```
For more details please see the [Changelog](https://github.com/modernweb-dev/rocket/blob/main/packages/plugins-manager/CHANGELOG.md#030) of the plugins-manager package.
## 0.5.6
### Patch Changes
- 0987a41: Fix styling in darkmode
## 0.5.5
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@rocket/launch",
"version": "0.5.5",
"version": "0.6.0",
"publishConfig": {
"access": "public"
},

View File

@@ -140,6 +140,7 @@ body[layout^='layout-home'] #main-header {
position: relative;
}
#main-header web-menu > nav,
#main-header .content-area {
display: flex;
justify-content: space-between;
@@ -155,6 +156,10 @@ body[layout^='layout-home'] #main-header {
order: 2;
}
#main-header web-menu {
order: 2;
}
#main-header a:hover {
color: var(--primary-color);
}
@@ -209,10 +214,15 @@ body[layout^='layout-home'] #main-header a:hover {
width: 100%;
}
#main-header web-menu > nav > a,
#main-header .content-area > * {
margin-right: 50px;
}
#main-header .content-area web-menu {
margin-right: 0;
}
#main-header .content-area > .social-link {
margin-right: 15px;
}
@@ -263,26 +273,26 @@ body[layout^='layout-home'] #main-header a:hover {
overflow: auto;
}
rocket-navigation .light-dark-switch {
web-menu[name="index"] .light-dark-switch {
margin-bottom: 10px;
}
rocket-navigation .light-dark-switch::part(label) {
web-menu[name="index"] .light-dark-switch::part(label) {
order: 10;
margin-left: 10px;
}
rocket-navigation a {
web-menu[name="index"] a {
text-decoration: none;
color: var(--primary-text-color);
}
rocket-navigation a:hover {
web-menu[name="index"] a:hover {
color: var(--primary-color);
}
/* line on the left to indicate current page */
rocket-navigation > ul > li > ul li.current ul li.anchor.current::before {
web-menu[name="index"] > nav > ul > li > ul li.current ul li.anchor.current::before {
content: '';
height: 1.6em;
width: 3px;
@@ -292,58 +302,47 @@ rocket-navigation > ul > li > ul li.current ul li.anchor.current::before {
margin-top: -2px;
}
rocket-navigation li {
web-menu[name="index"] li {
padding: 7px 0;
}
rocket-navigation > ul > li > ul li.current a:not(.anchor) {
web-menu[name="index"] > nav > ul > li > ul li.current a:not(.anchor) {
font-weight: bold;
}
rocket-navigation > ul > li > ul > li.current > ul > li > a {
web-menu[name="index"] > nav > ul > li > ul > li.current > ul > li > a {
font-weight: normal;
}
rocket-navigation hr {
web-menu[name="index"] hr {
margin: 30px -10px 10px -10px;
}
/* Hide below 3rd level by default */
rocket-navigation > ul > li > ul > li ul {
display: none;
}
/* Only show below 3rd level if level above is active/current */
li.current > ul,
li.active > ul {
display: block;
}
rocket-navigation > ul > li > a {
web-menu[name="index"] > nav > ul > li > span {
color: var(--primary-color);
font-weight: bold;
font-size: 18px;
text-transform: uppercase;
}
rocket-navigation > ul > li > ul a {
web-menu[name="index"] > nav > ul > li > ul a {
font-weight: normal;
}
rocket-navigation {
web-menu[name="index"] {
overflow: auto;
display: block;
margin-top: 40px;
padding: 0 20px;
}
rocket-navigation ul {
web-menu[name="index"] ul {
padding: 7px 0 10px 15px;
margin: 0;
list-style-type: none;
}
rocket-navigation > ul {
web-menu[name="index"] > nav > ul {
padding: 0;
position: relative;
}
@@ -422,7 +421,7 @@ li.current > ul > li.anchor {
display: none;
}
rocket-navigation {
web-menu[name="index"] {
padding: 0 25px 0 0;
}
@@ -433,7 +432,7 @@ li.current > ul > li.anchor {
}
/* for blog detail page */
rocket-navigation h3 {
web-menu[name="index"] h3 {
font-family: var(--heading-font-family, var(--primary-font-family));
font-size: 16px;
margin: 0 0 7px 0;

View File

@@ -1,4 +1,3 @@
import '@rocket/navigation/rocket-navigation.js';
import '@rocket/drawer/rocket-drawer.js';
const drawer = document.querySelector('#sidebar');

View File

@@ -5,6 +5,7 @@ html {
--primary-color-accent: #cee5f6;
--primary-text-color: #2c3e50;
--primary-lines-color: #ccc;
--primary-text-inverse-color: #eee;
/* Contrast colors */
--contrast-color-light: #fff;
@@ -19,6 +20,10 @@ html {
--primary-font-family: 'Open Sans', sans-serif;
--secondary-font-family: 'Montserrat', sans-serif;
--monospace-font-family: 'SFMono-Regular', 'Consolas', 'Liberation Mono', 'Menlo', 'Courier', monospace;
/* controls */
--switch-unselected-color: #808080;
--switch-selected-color: #42b983;
}
html.dark {
@@ -27,6 +32,7 @@ html.dark {
--primary-color-darker: #a22831;
--primary-color-accent: #cee5f6;
--primary-text-color: #eee;
--primary-text-inverse-color: #2c3e50;
/* Contrast colors */
--contrast-color-light: #fff;
@@ -39,6 +45,10 @@ html.dark {
/* typography */
--text-color: white;
/* controls */
--switch-unselected-color: #808080;
--switch-selected-color: #42b983;
/* markdown */
--markdown-octicon-link: white;
--markdown-syntax-background-color: #a0a0a0;

View File

@@ -1,8 +1,2 @@
<rocket-navigation>
{{ collections[section] | rocketNav | rocketNavToHtml({
listItemClass: "menu-item",
activeListItemClass: "current",
activeKey: eleventyNavigation.key
}) | safe }}
{% include 'partials/mobile-sidebar-bottom.njk' %}
</rocket-navigation>
<web-menu name="index"></web-menu>
{% include 'partials/mobile-sidebar-bottom.njk' %}

View File

@@ -1,8 +0,0 @@
{% if layout === "home.njk" and rocketLaunch.homeLayout === "background" %}
<a class="logo-link" href="{{ '/' | url }}">
<img src="{{ '/_assets/logo.svg' | asset | url }}" alt="{{ site.logoAlt }}" />
<span class="sr-only">{{ site.name }}</span>
</a>
{% else %}
{% include 'partials/_shared/logoLink.njk' %}
{% endif %}

View File

@@ -1,6 +0,0 @@
{%- for entry in collections.header %}
<a href="{{ entry.url | url }}" class="
{% if entry.url == page.url %} current {% endif %}
{% if page.url and page.url.search and (page.url.search(entry.url) !== -1) and (page.url !== '/') %} active {% endif %}
">{{ entry.data.eleventyNavigation.key }}</a>
{%- endfor %}

Some files were not shown because too many files have changed in this diff Show More