Compare commits

..

18 Commits

Author SHA1 Message Date
Benny Powers
d44a23af0c Merge pull request #83 from modernweb-dev/changeset-release/main
Version Packages
2021-03-07 10:14:39 +02:00
github-actions[bot]
18a79589c2 Version Packages 2021-03-06 19:28:35 +00:00
Thomas Allmer
b7727b0e10 chore: add rocket nav upgrade to cli 2021-03-06 20:26:44 +01:00
Thomas Allmer
5edc40fed5 feat(cli): make sure each instance has its own eleventy config 2021-03-06 19:58:09 +01:00
Amin Yahyaabadi
be0d0b3ca1 fix: add missing main entry to the packages (#81)
This allows the tools to work properly. For example, eslint-plugin-import, TypeScript LSP hyperclick, and many other tools rely on main.
2021-03-06 19:10:49 +01:00
Thomas Allmer
ef8ebb0098 feat(eleventy-rocket-nav): support dynamically created content 2021-03-06 19:05:00 +01:00
djlauk
2fa61e1377 chore: tiny fixes to the README (#74) 2021-02-23 21:45:41 +01:00
Matsuuu
b23e37f38e feat(search): Precache search results to service worker 2021-02-23 21:44:53 +01:00
Matsuuu
cf45e32702 feat(search): Add ellipsis as prefix when truncating 2021-02-23 21:44:53 +01:00
Matsuuu
b5965c6c37 feat(search): Set cursor to pointer on result hover 2021-02-23 21:44:53 +01:00
Matsuuu
e39cc45d23 fix(search): Center search icon 2021-02-23 21:44:53 +01:00
Matsuuu
f0434cb12c feat(search): Add feedback when no results found 2021-02-23 21:44:53 +01:00
Matsuuu
c87caaed2d feat: Allow overlay query modification in Drawer (#73) 2021-02-23 21:31:12 +01:00
Thomas Allmer
04af7ecf53 chore: align dependency versions 2021-02-23 20:39:37 +01:00
github-actions[bot]
98d6aad12a Version Packages 2021-02-05 13:30:10 +01:00
Thomas Allmer
ee6b404aaa fix: mdjs element pass on shadowRoot to story function 2021-02-05 13:26:42 +01:00
Thomas Allmer
8ba8939c67 chore: use test-helper everywhere 2021-02-04 20:48:08 +01:00
Thomas Allmer
8e095b792e fix(cli): watching user preset files to trigger updates automatically 2021-02-04 19:56:56 +01:00
44 changed files with 607 additions and 271 deletions

View File

@@ -43,7 +43,7 @@
## The Goal for Rocket ## The Goal for Rocket
> Our goal is to provide developers with a meta framework for static websites with a spricle of JavaScript. > Our goal is to provide developers with a meta framework for static websites with a sprinkle of JavaScript.
Get a site up and running in no time and focus on the content. Get a site up and running in no time and focus on the content.
You can still tweak every detail of every underlying tool that gets used. You can still tweak every detail of every underlying tool that gets used.
@@ -54,7 +54,7 @@ Rocket is part of the [Modern Web Family](https://twitter.com/modern_web_dev).
We are always looking for contributors of all skill levels! If you're looking to ease your way into the project, try out a [good first issue](https://github.com/modernweb-dev/rocket/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). We are always looking for contributors of all skill levels! If you're looking to ease your way into the project, try out a [good first issue](https://github.com/modernweb-dev/rocket/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
If you are interested in helping contribute to Modern Web, please take a look at our [Contributing Guide](https://github.com/modernweb-dev/rocket/blob/main/CONTRIBUTING.md). Also, feel free to drop into [slack](https://rocket.modern-web.dev/discover/slack/) and say hi. 👋 If you are interested in helping contribute to Modern Web, please take a look at our [Contributing Guide](https://github.com/modernweb-dev/rocket/blob/main/CONTRIBUTING.md). Also, feel free to drop into [slack](https://rocket.modern-web.dev/about/slack/) and say hi. 👋
### Financial Contributors ### Financial Contributors

View File

@@ -1,5 +1,11 @@
# @rocket/building-rollup # @rocket/building-rollup
## 0.1.3
### Patch Changes
- be0d0b3: fix: add missing main entry to the packages
## 0.1.2 ## 0.1.2
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@rocket/building-rollup", "name": "@rocket/building-rollup",
"version": "0.1.2", "version": "0.1.3",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -14,6 +14,7 @@
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)", "author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
"homepage": "https://rocket.modern-web.dev/docs/tools/building-rollup/", "homepage": "https://rocket.modern-web.dev/docs/tools/building-rollup/",
"type": "module", "type": "module",
"main": "./index.js",
"exports": { "exports": {
".": "./index.js" ".": "./index.js"
}, },

View File

@@ -53,7 +53,7 @@ export function createSpaMetaConfig(userConfig = { output: {} }) {
// directory to match patterns against to be precached // directory to match patterns against to be precached
globDirectory: path.join(config.output.dir), globDirectory: path.join(config.output.dir),
// cache any html js and css by default // cache any html js and css by default
globPatterns: ['**/*.{html,js,css,webmanifest}'], globPatterns: ['**/*.{html,js,css,webmanifest}', '**/*-search-index.json'],
skipWaiting: true, skipWaiting: true,
clientsClaim: true, clientsClaim: true,
runtimeCaching: [ runtimeCaching: [

View File

@@ -1,5 +1,11 @@
# check-html-links # check-html-links
## 0.2.1
### Patch Changes
- be0d0b3: fix: add missing main entry to the packages
## 0.2.0 ## 0.2.0
### Minor Changes ### Minor Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "check-html-links", "name": "check-html-links",
"version": "0.2.0", "version": "0.2.1",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -17,6 +17,7 @@
"check-html-links": "src/cli.js" "check-html-links": "src/cli.js"
}, },
"type": "module", "type": "module",
"main": "./index.js",
"exports": { "exports": {
".": "./index.js" ".": "./index.js"
}, },

View File

@@ -1,5 +1,33 @@
# @rocket/cli # @rocket/cli
## 0.6.0
### Minor Changes
- 5edc40f: Make sure each rocket instance has it's own eleventy config'
- ef8ebb0: To support dynamically created content to be part of the anchor navigation of the page we now analyze the final html output instead of `entry.templateContent`.
BREAKING CHANGE:
- only add anchors for the currently active pages (before it added anchor for every page)
### Patch Changes
- be0d0b3: fix: add missing main entry to the packages
- Updated dependencies [be0d0b3]
- Updated dependencies [ef8ebb0]
- @rocket/building-rollup@0.1.3
- check-html-links@0.2.1
- @rocket/core@0.1.2
- plugins-manager@0.2.1
- @rocket/eleventy-rocket-nav@0.3.0
## 0.5.2
### Patch Changes
- 8e095b7: Watching `_assets`, `_data`, `_includes` for changes to trigger updated automatically
## 0.5.1 ## 0.5.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@rocket/cli", "name": "@rocket/cli",
"version": "0.5.1", "version": "0.6.0",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -17,6 +17,7 @@
"rocket": "src/cli.js" "rocket": "src/cli.js"
}, },
"type": "module", "type": "module",
"main": "./index.cjs",
"exports": { "exports": {
".": { ".": {
"require": "./index.cjs", "require": "./index.cjs",
@@ -56,22 +57,22 @@
"dependencies": { "dependencies": {
"@11ty/eleventy": "^0.11.1", "@11ty/eleventy": "^0.11.1",
"@11ty/eleventy-img": "^0.7.4", "@11ty/eleventy-img": "^0.7.4",
"@rocket/building-rollup": "^0.1.2", "@rocket/building-rollup": "^0.1.3",
"@rocket/core": "^0.1.1", "@rocket/core": "^0.1.2",
"@rocket/eleventy-plugin-mdjs-unified": "^0.3.1", "@rocket/eleventy-plugin-mdjs-unified": "^0.3.1",
"@rocket/eleventy-rocket-nav": "^0.2.1", "@rocket/eleventy-rocket-nav": "^0.3.0",
"@rollup/plugin-babel": "^5.2.2", "@rollup/plugin-babel": "^5.2.2",
"@rollup/plugin-node-resolve": "^11.0.1", "@rollup/plugin-node-resolve": "^11.0.1",
"@web/config-loader": "^0.1.3", "@web/config-loader": "^0.1.3",
"@web/dev-server": "^0.1.4", "@web/dev-server": "^0.1.4",
"@web/dev-server-rollup": "^0.3.2", "@web/dev-server-rollup": "^0.3.2",
"@web/rollup-plugin-copy": "^0.2.0", "@web/rollup-plugin-copy": "^0.2.0",
"check-html-links": "^0.2.0", "check-html-links": "^0.2.1",
"command-line-args": "^5.1.1", "command-line-args": "^5.1.1",
"command-line-usage": "^6.1.1", "command-line-usage": "^6.1.1",
"fs-extra": "^9.0.1", "fs-extra": "^9.0.1",
"micromatch": "^4.0.2", "micromatch": "^4.0.2",
"plugins-manager": "^0.2.0", "plugins-manager": "^0.2.1",
"utf8": "^3.0.0" "utf8": "^3.0.0"
}, },
"types": "dist-types/index.d.ts" "types": "dist-types/index.d.ts"

View File

@@ -10,6 +10,7 @@ import computedConfigPkg from './public/computedConfig.cjs';
import path from 'path'; import path from 'path';
import Eleventy from '@11ty/eleventy'; import Eleventy from '@11ty/eleventy';
import TemplateConfig from '@11ty/eleventy/src/TemplateConfig.js';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import fs from 'fs-extra'; import fs from 'fs-extra';
@@ -33,6 +34,35 @@ export class RocketEleventy extends Eleventy {
await super.write(); await super.write();
await this.__rocketCli.update(); await this.__rocketCli.update();
} }
// forks it so we can watch for changes but don't include them while building
getChokidarConfig() {
let ignores = this.eleventyFiles.getGlobWatcherIgnores();
const keepWatching = [
path.join(this.__rocketCli.config._inputDirCwdRelative, '_assets', '**'),
path.join(this.__rocketCli.config._inputDirCwdRelative, '_data', '**'),
path.join(this.__rocketCli.config._inputDirCwdRelative, '_includes', '**'),
];
ignores = ignores.filter(ignore => !keepWatching.includes(ignore));
// debug("Ignoring watcher changes to: %o", ignores);
let configOptions = this.config.chokidarConfig;
// cant override these yet
// TODO maybe if array, merge the array?
delete configOptions.ignored;
return Object.assign(
{
ignored: ignores,
ignoreInitial: true,
// also interesting: awaitWriteFinish
},
configOptions,
);
}
} }
export class RocketCli { export class RocketCli {
@@ -70,11 +100,16 @@ export class RocketCli {
await this.mergePresets(); await this.mergePresets();
const elev = new RocketEleventy(_inputDirCwdRelative, outputDevDir, this); const elev = new RocketEleventy(_inputDirCwdRelative, outputDevDir, this);
elev.isVerbose = false;
// 11ty always wants a relative path to cwd - why? // 11ty always wants a relative path to cwd - why?
const rel = path.relative(process.cwd(), path.join(__dirname)); const rel = path.relative(process.cwd(), path.join(__dirname));
const relCwdPathToConfig = path.join(rel, 'shared', '.eleventy.cjs'); const relCwdPathToConfig = path.join(rel, 'shared', '.eleventy.cjs');
const config = new TemplateConfig(null, relCwdPathToConfig);
elev.config = config.getConfig();
elev.resetConfig();
elev.setConfigPathOverride(relCwdPathToConfig); elev.setConfigPathOverride(relCwdPathToConfig);
elev.isVerbose = false;
await elev.init(); await elev.init();
this.eleventy = elev; this.eleventy = elev;

View File

@@ -55,6 +55,10 @@ export async function readOutput(
type = 'build', type = 'build',
} = {}, } = {},
) { ) {
if (!cli || !cli.config) {
throw new Error(`No valid cli provided to readOutput - you passed a ${typeof cli}: ${cli}`);
}
const outputDir = type === 'build' ? cli.config.outputDir : cli.config.outputDevDir; const outputDir = type === 'build' ? cli.config.outputDir : cli.config.outputDevDir;
let text = await fs.promises.readFile(path.join(outputDir, fileName)); let text = await fs.promises.readFile(path.join(outputDir, fileName));
text = text.toString(); text = text.toString();
@@ -116,6 +120,7 @@ export async function execute(cli, configFileDir) {
await cli.setup(); await cli.setup();
cli.config.outputDevDir = path.join(configFileDir, '__output-dev'); cli.config.outputDevDir = path.join(configFileDir, '__output-dev');
cli.config.devServer.open = false; cli.config.devServer.open = false;
cli.config.devServer.port = 8080;
cli.config.watch = false; cli.config.watch = false;
cli.config.outputDir = path.join(configFileDir, '__output'); cli.config.outputDir = path.join(configFileDir, '__output');
await cli.run(); await cli.run();

View File

@@ -4,7 +4,6 @@ import {
executeBuild, executeBuild,
executeStart, executeStart,
readBuildOutput, readBuildOutput,
readOutput,
readStartOutput, readStartOutput,
setFixtureDir, setFixtureDir,
} from '@rocket/cli/test-helpers'; } from '@rocket/cli/test-helpers';
@@ -29,37 +28,27 @@ describe('RocketCli computedConfig', () => {
it('will extract a title from markdown and set first folder as section', async () => { it('will extract a title from markdown and set first folder as section', async () => {
cli = await executeStart('computed-config-fixtures/headlines/rocket.config.js'); cli = await executeStart('computed-config-fixtures/headlines/rocket.config.js');
const indexHtml = await readOutput(cli, 'index.html', { const indexHtml = await readStartOutput(cli, 'index.html');
type: 'start',
});
const [indexTitle, indexSection] = indexHtml.split('\n'); const [indexTitle, indexSection] = indexHtml.split('\n');
expect(indexTitle).to.equal('Root'); expect(indexTitle).to.equal('Root');
expect(indexSection).to.be.undefined; expect(indexSection).to.be.undefined;
const subHtml = await readOutput(cli, 'sub/index.html', { const subHtml = await readStartOutput(cli, 'sub/index.html');
type: 'start',
});
const [subTitle, subSection] = subHtml.split('\n'); const [subTitle, subSection] = subHtml.split('\n');
expect(subTitle).to.equal('Root: Sub'); expect(subTitle).to.equal('Root: Sub');
expect(subSection).to.equal('sub'); expect(subSection).to.equal('sub');
const subSubHtml = await readOutput(cli, 'sub/subsub/index.html', { const subSubHtml = await readStartOutput(cli, 'sub/subsub/index.html');
type: 'start',
});
const [subSubTitle, subSubSection] = subSubHtml.split('\n'); const [subSubTitle, subSubSection] = subSubHtml.split('\n');
expect(subSubTitle).to.equal('Sub: SubSub'); expect(subSubTitle).to.equal('Sub: SubSub');
expect(subSubSection).to.equal('sub'); expect(subSubSection).to.equal('sub');
const sub2Html = await readOutput(cli, 'sub2/index.html', { const sub2Html = await readStartOutput(cli, 'sub2/index.html');
type: 'start',
});
const [sub2Title, sub2Section] = sub2Html.split('\n'); const [sub2Title, sub2Section] = sub2Html.split('\n');
expect(sub2Title).to.equal('Root: Sub2'); expect(sub2Title).to.equal('Root: Sub2');
expect(sub2Section).to.equal('sub2'); expect(sub2Section).to.equal('sub2');
const withDataHtml = await readOutput(cli, 'with-data/index.html', { const withDataHtml = await readStartOutput(cli, 'with-data/index.html');
type: 'start',
});
const [withDataTitle, withDataSection] = withDataHtml.split('\n'); const [withDataTitle, withDataSection] = withDataHtml.split('\n');
expect(withDataTitle).to.equal('Set via data'); expect(withDataTitle).to.equal('Set via data');
expect(withDataSection).be.undefined; expect(withDataSection).be.undefined;
@@ -199,9 +188,7 @@ describe('RocketCli computedConfig', () => {
it('can be configured via setupEleventyComputedConfig', async () => { it('can be configured via setupEleventyComputedConfig', async () => {
cli = await executeStart('computed-config-fixtures/setup/addPlugin.rocket.config.js'); cli = await executeStart('computed-config-fixtures/setup/addPlugin.rocket.config.js');
const indexHtml = await readOutput(cli, 'index.html', { const indexHtml = await readStartOutput(cli, 'index.html');
type: 'start',
});
expect(indexHtml).to.equal('test-value'); expect(indexHtml).to.equal('test-value');
}); });

View File

@@ -1,86 +1,25 @@
import chai from 'chai'; import chai from 'chai';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import { RocketCli } from '../src/RocketCli.js';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs-extra';
import chalk from 'chalk'; import chalk from 'chalk';
import {
const __dirname = path.dirname(fileURLToPath(import.meta.url)); executeBuild,
executeLint,
executeStart,
expectThrowsAsync,
readBuildOutput,
readStartOutput,
setFixtureDir,
} from '@rocket/cli/test-helpers';
const { expect } = chai; const { expect } = chai;
/**
* @param {function} method
* @param {string} errorMessage
*/
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);
}
}
describe('RocketCli e2e', () => { describe('RocketCli e2e', () => {
let cli; let cli;
async function readOutput(
fileName,
{
stripServiceWorker = false,
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 (stripServiceWorker) {
const scriptOpenTagEnd = text.indexOf('<script inject-service-worker');
const scriptCloseTagStart = text.indexOf('</script>', scriptOpenTagEnd) + 9;
text = text.substring(0, scriptOpenTagEnd) + text.substring(scriptCloseTagStart);
}
if (stripStartEndWhitespace) {
text = text.trim();
}
return text;
}
async function execute() {
await cli.setup();
cli.config.outputDevDir = path.join(__dirname, 'e2e-fixtures', '__output-dev');
cli.config.devServer.open = false;
cli.config.devServer.port = 8080;
cli.config.watch = false;
cli.config.outputDir = path.join(__dirname, 'e2e-fixtures', '__output');
await cli.run();
}
async function executeLint(pathToConfig) {
cli = new RocketCli({
argv: ['lint', '--config-file', path.join(__dirname, pathToConfig.split('/').join(path.sep))],
});
await execute();
}
before(() => { before(() => {
// ignore colors in tests as most CIs won't support it // ignore colors in tests as most CIs won't support it
chalk.level = 0; chalk.level = 0;
setFixtureDir(import.meta.url);
}); });
afterEach(async () => { afterEach(async () => {
@@ -90,79 +29,39 @@ describe('RocketCli e2e', () => {
}); });
it('can add a unified plugin via the config', async () => { it('can add a unified plugin via the config', async () => {
cli = new RocketCli({ cli = await executeStart('e2e-fixtures/unified-plugin/rocket.config.js');
argv: [ const indexHtml = await readStartOutput(cli, 'index.html');
'build',
'--config-file',
path.join(__dirname, 'e2e-fixtures', 'unified-plugin', 'rocket.config.js'),
],
});
await execute();
const indexHtml = await readOutput('index.html', {
stripServiceWorker: true,
stripToBody: true,
});
expect(indexHtml).to.equal('<p>See a 🐶</p>'); expect(indexHtml).to.equal('<p>See a 🐶</p>');
}); });
describe('eleventy in config', () => { describe('eleventy in config', () => {
// TODO: find out while this has a side effect and breaks other tests it('can modify eleventy via an elventy function in the config', async () => {
it.skip('can modify eleventy via an elventy function in the config', async () => { cli = await executeStart('e2e-fixtures/content/eleventy.rocket.config.js');
cli = new RocketCli({ const indexHtml = await readStartOutput(cli, 'index.html');
argv: [
'start',
'--config-file',
path.join(__dirname, 'e2e-fixtures', 'content', 'eleventy.rocket.config.js'),
],
});
await execute();
const indexHtml = await readOutput('index.html', {
type: 'start',
});
expect(indexHtml).to.equal( expect(indexHtml).to.equal(
['# BEFORE #', '<p>Content inside <code>docs/index.md</code></p>'].join('\n'), ['# BEFORE #', '<p>Content inside <code>docs/index.md</code></p>'].join('\n'),
); );
}); });
it('will throw if you try to set options by returning an object', async () => { it('will throw if you try to set options by returning an object', async () => {
cli = new RocketCli({ await expectThrowsAsync(
argv: [ () => executeStart('e2e-fixtures/content/eleventy-return.rocket.config.js'),
'start', {
'--config-file', errorMatch: /Error in your Eleventy config file.*/,
path.join(__dirname, 'e2e-fixtures', 'content', 'eleventy-return.rocket.config.js'), },
], );
});
await expectThrowsAsync(() => execute(), {
errorMatch: /Error in your Eleventy config file.*/,
});
}); });
}); });
describe('setupDevAndBuildPlugins in config', () => { describe('setupDevAndBuildPlugins in config', () => {
it('can add a rollup plugin via setupDevAndBuildPlugins for build command', async () => { it('can add a rollup plugin via setupDevAndBuildPlugins for build command', async () => {
cli = new RocketCli({ cli = await executeBuild('e2e-fixtures/rollup-plugin/devbuild.rocket.config.js');
argv: [ const inlineModule = await readBuildOutput(cli, 'e97af63d.js');
'build',
'--config-file',
path.join(__dirname, 'e2e-fixtures', 'rollup-plugin', 'devbuild.rocket.config.js'),
],
});
await execute();
const inlineModule = await readOutput('e97af63d.js');
expect(inlineModule).to.equal('var a={test:"data"};console.log(a);'); expect(inlineModule).to.equal('var a={test:"data"};console.log(a);');
}); });
it('can add a rollup plugin via setupDevAndBuildPlugins for start command', async () => { it('can add a rollup plugin via setupDevAndBuildPlugins for start command', async () => {
cli = new RocketCli({ cli = await executeStart('e2e-fixtures/rollup-plugin/devbuild.rocket.config.js');
argv: [
'start',
'--config-file',
path.join(__dirname, 'e2e-fixtures', 'rollup-plugin', 'devbuild.rocket.config.js'),
],
});
await execute();
const response = await fetch('http://localhost:8080/test-data.json'); const response = await fetch('http://localhost:8080/test-data.json');
expect(response.ok).to.be.true; // no server error expect(response.ok).to.be.true; // no server error
@@ -173,88 +72,45 @@ describe('RocketCli e2e', () => {
}); });
it('can add a rollup plugin for dev & build and modify a build only plugin via the config', async () => { it('can add a rollup plugin for dev & build and modify a build only plugin via the config', async () => {
cli = new RocketCli({ cli = await executeBuild('e2e-fixtures/rollup-plugin/devbuild-build.rocket.config.js');
argv: [ const inlineModule = await readBuildOutput(cli, 'e97af63d.js');
'build',
'--config-file',
path.join(__dirname, 'e2e-fixtures', 'rollup-plugin', 'devbuild-build.rocket.config.js'),
],
});
await execute();
const inlineModule = await readOutput('e97af63d.js');
expect(inlineModule).to.equal('var a={test:"data"};console.log(a);'); expect(inlineModule).to.equal('var a={test:"data"};console.log(a);');
const swCode = await readOutput('my-service-worker.js'); const swCode = await readBuildOutput(cli, 'my-service-worker.js');
expect(swCode).to.not.be.undefined; expect(swCode).to.not.be.undefined;
}); });
it('can adjust the inputDir', async () => { it('can adjust the inputDir', async () => {
cli = new RocketCli({ cli = await executeStart('e2e-fixtures/change-input-dir/rocket.config.js');
argv: [
'start',
'--config-file',
path.join(__dirname, 'e2e-fixtures', 'change-input-dir', 'rocket.config.js'),
],
});
await execute();
const indexHtml = await readOutput('index.html', { const indexHtml = await readStartOutput(cli, 'index.html');
type: 'start',
});
expect(indexHtml).to.equal('<p>Markdown in <code>docs/page/index.md</code></p>'); 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 () => { it('can access main rocket config values via {{rocketConfig.value}}', async () => {
cli = new RocketCli({ cli = await executeStart('e2e-fixtures/rocket-config-in-template/rocket.config.js');
argv: [
'start',
'--config-file',
path.join(__dirname, 'e2e-fixtures', 'rocket-config-in-template', 'rocket.config.js'),
],
});
await execute();
const indexHtml = await readOutput('index.html', { const indexHtml = await readStartOutput(cli, 'index.html');
type: 'start',
});
expect(indexHtml).to.equal( 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>', '<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 () => { it('can add a pathPrefix that will not influence the start command', async () => {
cli = new RocketCli({ cli = await executeStart('e2e-fixtures/content/pathPrefix.rocket.config.js');
argv: [
'start',
'--config-file',
path.join(__dirname, 'e2e-fixtures', 'content', 'pathPrefix.rocket.config.js'),
],
});
await execute();
const linkHtml = await readOutput('link/index.html', { const linkHtml = await readStartOutput(cli, 'link/index.html');
type: 'start',
});
expect(linkHtml).to.equal( expect(linkHtml).to.equal(
['<p><a href="../">home</a></p>', '<p><a href="/">absolute home</a></p>'].join('\n'), ['<p><a href="../">home</a></p>', '<p><a href="/">absolute home</a></p>'].join('\n'),
); );
const assetHtml = await readOutput('use-assets/index.html', { const assetHtml = await readStartOutput(cli, 'use-assets/index.html');
type: 'start',
});
expect(assetHtml).to.equal('<link rel="stylesheet" href="/_merged_assets/some.css">'); expect(assetHtml).to.equal('<link rel="stylesheet" href="/_merged_assets/some.css">');
}); });
it('can add a pathPrefix that will be used in the build command', async () => { it('can add a pathPrefix that will be used in the build command', async () => {
cli = new RocketCli({ cli = await executeBuild('e2e-fixtures/content/pathPrefix.rocket.config.js');
argv: [
'build',
'--config-file',
path.join(__dirname, 'e2e-fixtures', 'content', 'pathPrefix.rocket.config.js'),
],
});
await execute();
const linkHtml = await readOutput('link/index.html', { const linkHtml = await readBuildOutput(cli, 'link/index.html', {
stripServiceWorker: true, stripServiceWorker: true,
stripToBody: true, stripToBody: true,
}); });
@@ -263,7 +119,7 @@ describe('RocketCli e2e', () => {
'\n', '\n',
), ),
); );
const assetHtml = await readOutput('use-assets/index.html', { const assetHtml = await readBuildOutput(cli, 'use-assets/index.html', {
stripServiceWorker: true, stripServiceWorker: true,
}); });
expect(assetHtml).to.equal( expect(assetHtml).to.equal(

View File

@@ -6,7 +6,7 @@ import json from '@rollup/plugin-json';
import { addPlugin, adjustPluginOptions } from 'plugins-manager'; import { addPlugin, adjustPluginOptions } from 'plugins-manager';
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const __dirname = path.dirname(fileURLToPath(import.meta.url));
const outputDir = path.join(__dirname, '..', '__output'); const outputDir = path.join(__dirname, '__output');
/** @type {Partial<import("../../../types/main").RocketCliOptions>} */ /** @type {Partial<import("../../../types/main").RocketCliOptions>} */
const config = { const config = {

View File

@@ -1,5 +1,11 @@
# @rocket/core # @rocket/core
## 0.1.2
### Patch Changes
- be0d0b3: fix: add missing main entry to the packages
## 0.1.1 ## 0.1.1
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@rocket/core", "name": "@rocket/core",
"version": "0.1.1", "version": "0.1.2",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -14,6 +14,7 @@
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)", "author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
"homepage": "https://rocket.modern-web.dev/", "homepage": "https://rocket.modern-web.dev/",
"type": "module", "type": "module",
"main": "./dist/title.cjs",
"exports": { "exports": {
"./title": { "./title": {
"require": "./dist/title.cjs", "require": "./dist/title.cjs",

View File

@@ -18,6 +18,7 @@ export class RocketDrawer extends OverlayMixin(LitElement) {
return { return {
useOverlay: { type: Boolean, reflect: true }, useOverlay: { type: Boolean, reflect: true },
useOverlayMediaQuery: { type: String }, useOverlayMediaQuery: { type: String },
mediaMatcher: { type: Object },
}; };
} }
@@ -89,6 +90,20 @@ export class RocketDrawer extends OverlayMixin(LitElement) {
} }
} }
} }
if (changedProperties.has('useOverlayMediaQuery')) {
this.mediaMatcher.removeEventListener('change', this.onMatchMedia);
this.mediaMatcher = window.matchMedia(this.useOverlayMediaQuery);
this.mediaMatcher.addEventListener('change', this.onMatchMedia);
this.useOverlay = !!this.mediaMatcher.matches;
}
}
/**
* @param { MediaQueryListEvent } query
*/
onMatchMedia(query) {
this.useOverlay = !!query.matches;
} }
_setupOpenCloseListeners() { _setupOpenCloseListeners() {
@@ -118,11 +133,15 @@ export class RocketDrawer extends OverlayMixin(LitElement) {
this.__toggle = this.__toggle.bind(this); this.__toggle = this.__toggle.bind(this);
this.onMatchMedia = this.onMatchMedia.bind(this);
this.onGestureStart = this.onGestureStart.bind(this); this.onGestureStart = this.onGestureStart.bind(this);
this.onGestureMove = this.onGestureMove.bind(this); this.onGestureMove = this.onGestureMove.bind(this);
this.onGestureEnd = this.onGestureEnd.bind(this); this.onGestureEnd = this.onGestureEnd.bind(this);
this.updateFromTouch = this.updateFromTouch.bind(this); this.updateFromTouch = this.updateFromTouch.bind(this);
this.mediaMatcher = window.matchMedia(this.useOverlayMediaQuery);
this.mediaMatcher.addEventListener('change', this.onMatchMedia);
this._startX = 0; this._startX = 0;
this._currentX = 0; this._currentX = 0;
this._velocity = 0; this._velocity = 0;
@@ -133,10 +152,7 @@ export class RocketDrawer extends OverlayMixin(LitElement) {
connectedCallback() { connectedCallback() {
super.connectedCallback(); super.connectedCallback();
this.useOverlay = !!window.matchMedia(this.useOverlayMediaQuery).matches; this.useOverlay = !!this.mediaMatcher.matches;
window.matchMedia(this.useOverlayMediaQuery).addListener(query => {
this.useOverlay = !!query.matches;
});
} }
render() { render() {

View File

@@ -1,4 +1,5 @@
const RocketNav = require('./eleventy-rocket-nav'); const RocketNav = require('./eleventy-rocket-nav');
const { addPageAnchors } = require('./src/addPageAnchors.js');
// export the configuration function for plugin // export the configuration function for plugin
module.exports = function (eleventyConfig) { module.exports = function (eleventyConfig) {
@@ -8,6 +9,10 @@ module.exports = function (eleventyConfig) {
eleventyConfig.addNunjucksFilter('rocketNavToHtml', function (pages, options) { eleventyConfig.addNunjucksFilter('rocketNavToHtml', function (pages, options) {
return RocketNav.toHtml.call(eleventyConfig, pages, options); return RocketNav.toHtml.call(eleventyConfig, pages, options);
}); });
eleventyConfig.addTransform('rocket-nav-add-page-anchors', async function (content) {
const newContent = await addPageAnchors(content);
return newContent;
});
}; };
module.exports.navigation = { module.exports.navigation = {

View File

@@ -1,5 +1,15 @@
# @rocket/eleventy-rocket-nav # @rocket/eleventy-rocket-nav
## 0.3.0
### Minor Changes
- ef8ebb0: To support dynamically created content to be part of the anchor navigation of the page we now analyze the final html output instead of `entry.templateContent`.
BREAKING CHANGE:
- only add anchors for the currently active pages (before it added anchor for every page)
## 0.2.1 ## 0.2.1
### Patch Changes ### Patch Changes

View File

@@ -94,21 +94,8 @@ function findNavigationEntries(nodes = [], key = '') {
entry.title = entry.key; entry.title = entry.key;
} }
if (entry.key) { if (entry.key) {
if (!headingsCache.has(entry.templateContent)) {
headingsCache.set(entry.templateContent, getHeadingsOfHtml(entry.templateContent));
}
const headings = /** @type {Heading[]} */ (headingsCache.get(entry.templateContent));
const anchors = headings.map(heading => ({
key: heading.text + Math.random(),
parent: entry.key,
url: `${entry.url}#${heading.id}`,
pluginType: 'eleventy-navigation',
parentKey: entry.key,
title: heading.text,
anchor: true,
}));
// @ts-ignore // @ts-ignore
entry.children = [...anchors, ...findNavigationEntries(nodes, entry.key)]; entry.children = findNavigationEntries(nodes, entry.key);
} }
return entry; return entry;
}); });
@@ -227,43 +214,36 @@ function navigationToHtml(pages, _options = {}) {
}>${pages }>${pages
.map(entry => { .map(entry => {
const liClass = []; const liClass = [];
const aClass = [];
if (options.listItemClass) { if (options.listItemClass) {
liClass.push(options.listItemClass); liClass.push(options.listItemClass);
} }
if (options.anchorClass) { if (options.activeKey === entry.key && options.activeListItemClass) {
aClass.push(options.anchorClass); liClass.push(options.activeListItemClass);
}
if (options.activeKey === entry.key) {
if (options.activeListItemClass) {
liClass.push(options.activeListItemClass);
}
if (options.activeAnchorClass) {
aClass.push(options.activeAnchorClass);
}
} }
if (options.activeTreeListClass && activePages && activePages.includes(entry.key)) { if (options.activeTreeListClass && activePages && activePages.includes(entry.key)) {
liClass.push(options.activeTreeListClass); liClass.push(options.activeTreeListClass);
} }
if (options.activeAnchorListClass && activePages && activePages.includes(entry.key)) {
aClass.push(options.activeAnchorListClass);
}
if (options.listItemHasChildrenClass && entry.children && entry.children.length) { if (options.listItemHasChildrenClass && entry.children && entry.children.length) {
liClass.push(options.listItemHasChildrenClass); liClass.push(options.listItemHasChildrenClass);
} }
if (entry.anchor) { const output = [];
liClass.push('anchor'); output.push(
aClass.push('anchor'); `<${options.listItemElement}${liClass.length ? ` class="${liClass.join(' ')}"` : ''}>`,
);
output.push(`<a href="${urlFilter(entry.url)}">${entry.title}</a>`);
if (options.showExcerpt && entry.excerpt) {
output.push(`: ${entry.excerpt}`);
} }
if (options.activeKey === entry.key && options.activeListItemClass) {
output.push('<!-- ADD PAGE ANCHORS -->');
}
if (entry.children) {
output.push(navigationToHtml(entry.children, options));
}
output.push(`</${options.listItemElement}>`);
return `<${options.listItemElement}${ return output.join('\n');
liClass.length ? ` class="${liClass.join(' ')}"` : ''
}><a href="${urlFilter(entry.url)}"${
aClass.length ? ` class="${aClass.join(' ')}"` : ''
}>${entry.title}</a>${options.showExcerpt && entry.excerpt ? `: ${entry.excerpt}` : ''}${
entry.children ? navigationToHtml(entry.children, options) : ''
}</${options.listItemElement}>`;
}) })
.join('\n')}</${options.listElement}>` .join('\n')}</${options.listElement}>`
: ''; : '';

View File

@@ -1,6 +1,6 @@
{ {
"name": "@rocket/eleventy-rocket-nav", "name": "@rocket/eleventy-rocket-nav",
"version": "0.2.1", "version": "0.3.0",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -13,7 +13,7 @@
}, },
"main": ".eleventy.js", "main": ".eleventy.js",
"scripts": { "scripts": {
"test": "mocha test-node/**/*.test.js test-node/*.test.js", "test": "mocha test-node/**/*.test.js test-node/*.test.js --timeout 5000",
"test:watch": "mocha test-node/**/*.test.js test-node/*.test.js --watch" "test:watch": "mocha test-node/**/*.test.js test-node/*.test.js --watch"
}, },
"files": [ "files": [

View File

@@ -0,0 +1,136 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
const fs = require('fs');
const { SaxEventType, SAXParser } = require('sax-wasm');
const saxPath = require.resolve('sax-wasm/lib/sax-wasm.wasm');
const saxWasmBuffer = fs.readFileSync(saxPath);
/** @typedef {import('../types').Heading} Heading */
/** @typedef {import('sax-wasm').Text} Text */
/** @typedef {import('sax-wasm').Tag} Tag */
/** @typedef {import('sax-wasm').Position} Position */
// Instantiate
const parser = new SAXParser(
SaxEventType.CloseTag | SaxEventType.Comment,
{ highWaterMark: 256 * 1024 }, // 256k chunks
);
/**
* @param {object} options
* @param {string} options.content
* @param {Position} options.start
* @param {Position} options.end
* @param {string} options.insert
*/
function removeBetween({ content, start, end, insert = '' }) {
const lines = content.split('\n');
const i = start.line;
const line = lines[i];
const upToChange = line.slice(0, start.character - 1);
const afterChange = line.slice(end.character + 2);
lines[i] = `${upToChange}${insert}${afterChange}`;
return lines.join('\n');
}
/**
* @param {Tag} data
* @param {string} name
*/
function getAttribute(data, name) {
if (data.attributes) {
const { attributes } = data;
const foundIndex = attributes.findIndex(entry => entry.name.value === name);
if (foundIndex !== -1) {
return attributes[foundIndex].value.value;
}
}
return null;
}
/**
* @param {Tag} data
*/
function getText(data) {
if (data.textNodes) {
return data.textNodes.map(textNode => textNode.value).join('');
}
return null;
}
/**
* @param {string} html
*/
function getHeadingsOfHtml(html) {
/** @type {Heading[]} */
const headings = [];
/** @type {Text} */
let insertPoint;
parser.eventHandler = (ev, _data) => {
if (ev === SaxEventType.Comment) {
const data = /** @type {Text} */ (/** @type {any} */ (_data));
// NOTE: we NEED to access data internal value so sax-wasm does not reuse it's value
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const tmp = data.start.line + data.end.line;
if (data.value.trim() === 'ADD PAGE ANCHORS' || data.value.trim() === '-->ADD PAGE ANCHORS') {
insertPoint = data;
}
}
if (ev === SaxEventType.CloseTag) {
const data = /** @type {Tag} */ (/** @type {any} */ (_data));
if (data.name === 'h2') {
const id = getAttribute(data, 'id');
const text = getText(data);
if (id && text) {
headings.push({ text, id });
}
}
}
};
parser.write(Buffer.from(html, 'utf8'));
parser.end();
// @ts-ignore
return { headings, insertPoint };
}
let isSetup = false;
/**
* @param {string} content
*/
async function addPageAnchors(content) {
if (!isSetup) {
await parser.prepareWasm(saxWasmBuffer);
isSetup = true;
}
const { headings, insertPoint } = getHeadingsOfHtml(content);
const pageAnchorsHtml = [];
if (headings.length > 0) {
pageAnchorsHtml.push('<ul>');
for (const heading of headings) {
pageAnchorsHtml.push(' <li class="menu-item anchor">');
pageAnchorsHtml.push(` <a href="#${heading.id}" class="anchor">${heading.text}</a>`);
pageAnchorsHtml.push(' </li>');
}
pageAnchorsHtml.push('</ul>');
}
if (insertPoint) {
return removeBetween({
content,
start: insertPoint.start,
end: insertPoint.end,
insert: pageAnchorsHtml.join('\n'),
});
}
return content;
}
module.exports = {
addPageAnchors,
};

View File

@@ -0,0 +1,32 @@
const { expect } = require('chai');
const prettier = require('prettier');
const { addPageAnchors } = require('../src/addPageAnchors.js');
const format = code => prettier.format(code, { parser: 'html' }).trim();
describe('addPageAnchors', () => {
it('finds and adds anchors for each h2 as an unordered list', async () => {
const input = [
'<body>',
' <!-- ADD PAGE ANCHORS -->',
' <div id="content">',
' <h2 id="first">👉 First Headline</h2>',
' </div>',
'</body>',
].join('\n');
const expected = [
'<body>',
' <ul>',
' <li class="menu-item anchor">',
' <a href="#first" class="anchor">👉 First Headline</a>',
' </li>',
' </ul>',
' <div id="content">',
' <h2 id="first">👉 First Headline</h2>',
' </div>',
'</body>',
].join('\n');
const result = await addPageAnchors(input);
expect(format(result)).to.deep.equal(expected);
});
});

View File

@@ -0,0 +1,5 @@
const eleventyNavigationPlugin = require('@rocket/eleventy-rocket-nav');
module.exports = function (eleventyConfig) {
eleventyConfig.addPlugin(eleventyNavigationPlugin);
};

View File

@@ -0,0 +1 @@
module.exports = 'layout.njk';

View File

@@ -0,0 +1,9 @@
<body>
{{ collections.all | rocketNav | rocketNavToHtml({
listItemClass: "menu-item",
activeListItemClass: "current",
activeKey: eleventyNavigation.key
}) | safe }}
{{ content | safe }}
</body>

View File

@@ -0,0 +1,9 @@
---
title: Bats
eleventyNavigation:
key: Bats
parent: Mammals
order: 2
---
🦇 can fly.

View File

@@ -0,0 +1,12 @@
---
title: Humans
eleventyNavigation:
key: Humans
parent: Mammals
order: 1
---
<h2 id="anatomy">Anatomy</h2>
<p>Has arms.</p>
<h2 id="age">📖 Age</h2>
<p>Up to 130 years.</p>

View File

@@ -0,0 +1,7 @@
---
title: Mammals
eleventyNavigation:
key: Mammals
---
Mammals need air.

View File

@@ -0,0 +1,96 @@
const path = require('path');
const fs = require('fs-extra');
const { expect } = require('chai');
const Eleventy = require('@11ty/eleventy');
const TemplateConfig = require('@11ty/eleventy/src/TemplateConfig');
const prettier = require('prettier');
async function execute(fixtureDir) {
const relPath = path.relative(process.cwd(), __dirname);
const relativeInputPath = path.join(relPath, fixtureDir.split('/').join(path.sep));
const relativeOutputPath = path.join(relPath, 'fixtures', '__output');
const relativeConfigPath = path.join(relativeInputPath, '.eleventy.js');
await fs.emptyDir(relativeOutputPath);
const elev = new Eleventy(relativeInputPath, relativeOutputPath);
const config = new TemplateConfig(null, relativeConfigPath);
elev.config = config.getConfig();
elev.setConfigPathOverride(relativeConfigPath);
elev.resetConfig();
await elev.init();
await elev.write();
return {
readOutput: async readPath => {
const relativeReadPath = path.join(relativeOutputPath, readPath);
let text = await fs.promises.readFile(relativeReadPath);
text = text.toString();
text = prettier.format(text, { parser: 'html', printWidth: 100 });
return text.trim();
},
};
}
describe('eleventy-rocket-nav', () => {
it('renders a menu with anchors for h2 content', async () => {
const { readOutput } = await execute('fixtures/three-pages');
const bats = await readOutput('bats/index.html');
expect(bats).to.deep.equal(
[
'<body>',
' <ul>',
' <li class="menu-item active">',
' <a href="/mammals/">Mammals</a>',
' <ul>',
' <li class="menu-item">',
' <a href="/humans/">Humans</a>',
' </li>',
' <li class="menu-item current">',
' <a href="/bats/">Bats</a>',
' </li>',
' </ul>',
' </li>',
' </ul>',
'',
' <p>🦇 can fly.</p>',
'</body>',
].join('\n'),
);
const humans = await readOutput('humans/index.html');
expect(humans).to.deep.equal(
[
'<body>',
' <ul>',
' <li class="menu-item active">',
' <a href="/mammals/">Mammals</a>',
' <ul>',
' <li class="menu-item current">',
' <a href="/humans/">Humans</a>',
' <ul>',
' <li class="menu-item anchor">',
' <a href="#anatomy" class="anchor">Anatomy</a>',
' </li>',
' <li class="menu-item anchor">',
' <a href="#age" class="anchor">📖 Age</a>',
' </li>',
' </ul>',
' </li>',
' <li class="menu-item">',
' <a href="/bats/">Bats</a>',
' </li>',
' </ul>',
' </li>',
' </ul>',
'',
' <h2 id="anatomy">Anatomy</h2>',
' <p>Has arms.</p>',
' <h2 id="age">📖 Age</h2>',
' <p>Up to 130 years.</p>',
'</body>',
].join('\n'),
);
});
});

View File

@@ -43,8 +43,8 @@
"remark" "remark"
], ],
"dependencies": { "dependencies": {
"@mdjs/mdjs-preview": "^0.3.0", "@mdjs/mdjs-preview": "^0.3.1",
"@mdjs/mdjs-story": "^0.1.0", "@mdjs/mdjs-story": "^0.1.1",
"@types/unist": "^2.0.3", "@types/unist": "^2.0.3",
"es-module-lexer": "^0.3.26", "es-module-lexer": "^0.3.26",
"github-markdown-css": "^4.0.0", "github-markdown-css": "^4.0.0",

View File

@@ -1,6 +1,19 @@
# @mdjs/mdjs-preview # @mdjs/mdjs-preview
## 0.3.2
### Patch Changes
- be0d0b3: fix: add missing main entry to the packages
## 0.3.1
### Patch Changes
- ee6b404: Pass on the shadowRoot to the story function
## 0.3.0 ## 0.3.0
### Minor Changes ### Minor Changes
- 15e0abe: Clean up dependencies - add Types - 15e0abe: Clean up dependencies - add Types

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mdjs/mdjs-preview", "name": "@mdjs/mdjs-preview",
"version": "0.3.0", "version": "0.3.2",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -13,6 +13,7 @@
}, },
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)", "author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
"homepage": "https://rocket.modern-web.dev/docs/markdown-javascript/preview/", "homepage": "https://rocket.modern-web.dev/docs/markdown-javascript/preview/",
"main": "./index.js",
"type": "module", "type": "module",
"exports": { "exports": {
".": "./index.js", ".": "./index.js",

View File

@@ -1,6 +1,19 @@
import { LitElement, html, css } from 'lit-element'; import { LitElement, html, css } from 'lit-element';
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
/**
* @typedef {object} StoryOptions
* @property {ShadowRoot | null} StoryOptions.shadowRoot
*/
/** @typedef {(options?: StoryOptions) => ReturnType<LitElement['render']>} LitHtmlStoryFn */
/**
* Renders a story within a preview frame
*
* @element mdjs-preview
* @prop {StoryFn} [story=(() => TemplateResult)] Function that returns the story
*/
export class MdJsPreview extends LitElement { export class MdJsPreview extends LitElement {
static get properties() { static get properties() {
return { return {
@@ -28,6 +41,7 @@ export class MdJsPreview extends LitElement {
constructor() { constructor() {
super(); super();
this.code = ''; this.code = '';
/** @type {LitHtmlStoryFn} */
this.story = () => html` <p>Loading...</p> `; this.story = () => html` <p>Loading...</p> `;
this.codeHasHtml = false; this.codeHasHtml = false;
} }
@@ -35,7 +49,7 @@ export class MdJsPreview extends LitElement {
render() { render() {
return html` return html`
<div id="wrapper"> <div id="wrapper">
<div>${this.story()}</div> <div>${this.story({ shadowRoot: this.shadowRoot })}</div>
<button id="showCodeButton" @click=${this.toggleShowCode}>show code</button> <button id="showCodeButton" @click=${this.toggleShowCode}>show code</button>
</div> </div>
${this.codeHasHtml ? unsafeHTML(this.code) : html`<pre><code>${this.code}</code></pre>`} ${this.codeHasHtml ? unsafeHTML(this.code) : html`<pre><code>${this.code}</code></pre>`}

View File

@@ -1,6 +1,19 @@
# @mdjs/mdjs-story # @mdjs/mdjs-story
## 0.1.2
### Patch Changes
- be0d0b3: fix: add missing main entry to the packages
## 0.1.1
### Patch Changes
- ee6b404: Pass on the shadowRoot to the story function
## 0.1.0 ## 0.1.0
### Minor Changes ### Minor Changes
- 15e0abe: Clean up dependencies - add Types - 15e0abe: Clean up dependencies - add Types

View File

@@ -1,6 +1,6 @@
{ {
"name": "@mdjs/mdjs-story", "name": "@mdjs/mdjs-story",
"version": "0.1.0", "version": "0.1.2",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -13,6 +13,7 @@
}, },
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)", "author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
"homepage": "https://rocket.modern-web.dev/docs/markdown-javascript/story/", "homepage": "https://rocket.modern-web.dev/docs/markdown-javascript/story/",
"main": "./index.js",
"type": "module", "type": "module",
"exports": { "exports": {
".": "./index.js", ".": "./index.js",

View File

@@ -1,5 +1,18 @@
import { LitElement, html } from 'lit-element'; import { LitElement, html } from 'lit-element';
/**
* @typedef {object} StoryOptions
* @property {ShadowRoot | null} StoryOptions.shadowRoot
*/
/** @typedef {(options?: StoryOptions) => ReturnType<LitElement['render']>} LitHtmlStoryFn */
/**
* Renders a story
*
* @element mdjs-story
* @prop {StoryFn} [story=(() => TemplateResult)] Function that returns the story
*/
export class MdJsStory extends LitElement { export class MdJsStory extends LitElement {
static get properties() { static get properties() {
return { return {
@@ -11,10 +24,11 @@ export class MdJsStory extends LitElement {
constructor() { constructor() {
super(); super();
this.story = () => html` <p>Loading...</p> `; /** @type {LitHtmlStoryFn} */
this.story = () => html`<p>Loading...</p>`;
} }
render() { render() {
return this.story(); return this.story({ shadowRoot: this.shadowRoot });
} }
} }

View File

@@ -1,5 +1,11 @@
# plugins-manager # plugins-manager
## 0.2.1
### Patch Changes
- be0d0b3: fix: add missing main entry to the packages
## 0.2.0 ## 0.2.0
### Minor Changes ### Minor Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "plugins-manager", "name": "plugins-manager",
"version": "0.2.0", "version": "0.2.1",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -14,6 +14,7 @@
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)", "author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
"homepage": "https://rocket.modern-web.dev/docs/tools/plugins-manager/", "homepage": "https://rocket.modern-web.dev/docs/tools/plugins-manager/",
"type": "module", "type": "module",
"main": "./dist/index.cjs",
"exports": { "exports": {
".": { ".": {
"require": "./dist/index.cjs", "require": "./dist/index.cjs",

View File

@@ -1,5 +1,13 @@
# @rocket/search # @rocket/search
## 0.3.1
### Patch Changes
- be0d0b3: fix: add missing main entry to the packages
- Updated dependencies [be0d0b3]
- plugins-manager@0.2.1
## 0.3.0 ## 0.3.0
### Minor Changes ### Minor Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@rocket/search", "name": "@rocket/search",
"version": "0.3.0", "version": "0.3.1",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
@@ -14,6 +14,7 @@
"author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)", "author": "Modern Web <hello@modern-web.dev> (https://modern-web.dev/)",
"homepage": "https://rocket.modern-web.dev/docs/presets/search/", "homepage": "https://rocket.modern-web.dev/docs/presets/search/",
"type": "module", "type": "module",
"main": "./node.js",
"exports": { "exports": {
".": "./node.js", ".": "./node.js",
"./node": "./node.js", "./node": "./node.js",
@@ -44,7 +45,7 @@
"@open-wc/scoped-elements": "^1.3.2", "@open-wc/scoped-elements": "^1.3.2",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"minisearch": "^3.0.2", "minisearch": "^3.0.2",
"plugins-manager": "^0.2.0", "plugins-manager": "^0.2.1",
"sax-wasm": "^2.0.0" "sax-wasm": "^2.0.0"
} }
} }

View File

@@ -29,7 +29,7 @@ function getTitle({ result, search }) {
function getText({ result, search }) { function getText({ result, search }) {
const { terms, body } = result; const { terms, body } = result;
return highlightSearchTerms({ text: body, search, terms }); return highlightSearchTerms({ text: body, search, terms, addEllipsis: true });
} }
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/40110 // @ts-expect-error https://github.com/microsoft/TypeScript/issues/40110
@@ -40,6 +40,7 @@ export class RocketSearch extends ScopedElementsMixin(LitElement) {
search: { type: String }, search: { type: String },
results: { type: Array }, results: { type: Array },
maxResults: { type: Number, attribute: 'max-results' }, maxResults: { type: Number, attribute: 'max-results' },
noResultsText: { type: String },
}; };
} }
@@ -55,6 +56,7 @@ export class RocketSearch extends ScopedElementsMixin(LitElement) {
this.jsonUrl = ''; this.jsonUrl = '';
this.search = ''; this.search = '';
this.maxResults = 10; this.maxResults = 10;
this.noResultsText = 'No results found';
/** /**
* @type {RocketSearchResult[]} * @type {RocketSearchResult[]}
*/ */
@@ -132,6 +134,9 @@ export class RocketSearch extends ScopedElementsMixin(LitElement) {
></rocket-search-option> ></rocket-search-option>
`, `,
)} )}
${this.results.length <= 0 && this.search.length > 0
? html` <rocket-search-option .title=${this.noResultsText}></rocket-search-option> `
: ''}
</rocket-search-combobox> </rocket-search-combobox>
`; `;
} }

View File

@@ -43,6 +43,8 @@ export class RocketSearchCombobox extends LionCombobox {
font: inherit; font: inherit;
cursor: pointer; cursor: pointer;
fill: var(--rocket-search-fill-color, #000); fill: var(--rocket-search-fill-color, #000);
display: flex;
align-items: center;
} }
::slotted([slot='prefix'][close-btn]) { ::slotted([slot='prefix'][close-btn]) {

View File

@@ -65,7 +65,7 @@ export class RocketSearchOption extends LinkMixin(LionOption) {
:host { :host {
display: block; display: block;
cursor: default; cursor: pointer;
position: relative; position: relative;
padding: 12px 10px; padding: 12px 10px;
display: flex; display: flex;

View File

@@ -26,6 +26,7 @@ function defaultHighlight(term) {
* @param {number} [options.before] * @param {number} [options.before]
* @param {number} [options.length] * @param {number} [options.length]
* @param {function} [options.highlight] * @param {function} [options.highlight]
* @param {boolean} [options.addEllipsis]
*/ */
export function highlightSearchTerms({ export function highlightSearchTerms({
search, search,
@@ -34,6 +35,7 @@ export function highlightSearchTerms({
before = 15, before = 15,
length = 100, length = 100,
highlight = defaultHighlight, highlight = defaultHighlight,
addEllipsis = false,
}) { }) {
if (!search || !text) { if (!search || !text) {
return ''; return '';
@@ -70,5 +72,9 @@ export function highlightSearchTerms({
} while (startIndex !== -1); } while (startIndex !== -1);
} }
return newText.substr(truncateStart, length + extraLength); let textResult = newText.substr(truncateStart, length + extraLength);
if (addEllipsis && truncateStart > 0) {
textResult = `...${textResult}`;
}
return textResult;
} }