add all docs content to the catalog

This commit is contained in:
Elliott Marquez 2023-09-22 23:05:50 -07:00
parent 446558081a
commit 186e8fc188
23 changed files with 383 additions and 66 deletions

4
.gitignore vendored
View File

@ -18,6 +18,10 @@ catalog/lib/
catalog/build/
catalog/site/components/*.md
catalog/site/components/images
catalog/site/theming/*.md
catalog/site/theming/images
catalog/site/about/*.md
catalog/site/about/images
catalog/*.tsbuildinfo
catalog/stories/*/
!catalog/stories/components/

View File

@ -0,0 +1,114 @@
/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
const cheerio = require('cheerio');
/**
* @param {import('cheerio').CheerioAPI} $
* @param {[RegExp|string, string,(match: string, ...pattern: string[]) => string]} redirects Any redirects we want to apply
*/
function fixLinks($, redirects) {
const anchors = $('a');
for (const anchor of anchors) {
const href = $(anchor).attr('href');
if (!href) continue;
const isExternal = href.startsWith('http');
if (isExternal) continue;
let [path, hash] = href.split('#');
for (const [pattern, replacement] of redirects) {
const regex = new RegExp(pattern);
path = path.replace(regex, replacement);
}
const endsWithMd = path.endsWith('.md');
if (endsWithMd) {
path = path.replace(/\.md$/, '/');
}
const endsWithSlash = path.endsWith('/');
if (!endsWithSlash) {
path += '/';
}
const newHref = path + (hash ? `#${hash}` : '');
$(anchor).attr('href', newHref);
}
}
/**
* @param {import('cheerio').CheerioAPI} $
*/
function blockquote($) {
const blockquotes = $('blockquote');
for (const blockquote of blockquotes) {
const $blockquote = $(blockquote);
const $first = $blockquote.children().first();
const text = $first.text().trim();
const iconRegex = /^(tip|important|note):\s*/i;
const match = text.match(iconRegex);
const hasIcon = match;
if (!hasIcon) {
$blockquote.addClass('none');
continue;
}
let newText = text.replace(iconRegex, '');
$first.text(newText);
const type = match[1].toLowerCase();
let icon = '';
switch (type) {
case 'tip':
$blockquote.addClass('tip');
icon = 'star';
break;
case 'important':
$blockquote.addClass('important');
icon = 'priority_high';
break;
case 'note':
$blockquote.addClass('note');
icon = 'bookmark';
break;
}
$blockquote.wrapInner('<div class="content"></div>');
$blockquote.prepend(`<div class="icon"><md-icon>${icon}</md-icon></div>`);
}
}
/**
* A filter that sanitizes <md-*> tags in a string so that they can be rendered
* as text in the TOC.
*
* @example
* ```html
* <!--
* Will filter out a TOC that has <md-*> tags in it
* -->
* {{ toc | filterToc | safe }}
* ```
*
* @param eleventyConfig The 11ty config in which to attach this filter.
* @param {[RegExp|string, string,(match: string, ...pattern: string[]) => string]} redirects Any redirects we want to apply
*/
function mdMarkdown(eleventyConfig, redirects) {
eleventyConfig.addFilter('mdMarkdown', function (html) {
const $ = cheerio.load(html);
fixLinks($, redirects);
blockquote($);
return $.html();
});
}
module.exports = mdMarkdown;

View File

@ -14,6 +14,7 @@ const pluginTOC = require('eleventy-plugin-nesting-toc');
const permalinks = require('./eleventy-helpers/plugins/permalinks.cjs');
const filterToc = require('./eleventy-helpers/filters/filter-toc.cjs');
const filterSort = require('./eleventy-helpers/filters/filter-sort.cjs');
const mdMarkdown = require('./eleventy-helpers/filters/md-markdown.cjs');
const copyCodeButtonPlugin = require('./eleventy-helpers/plugins/copy-code-button.cjs');
const markdownIt = require('markdown-it');
const { compress } = require('eleventy-plugin-compress');
@ -36,7 +37,9 @@ module.exports = function (eleventyConfig) {
// the stories files in the source to this directory
.addPassthroughCopy({ 'stories/': 'assets/stories/' })
// These images are generated by the docs copy step in wireit
.addPassthroughCopy('site/components/images');
.addPassthroughCopy('site/components/images')
.addPassthroughCopy('site/theming/images')
.addPassthroughCopy('site/about/images');
// add the lit-ssr plugin
eleventyConfig.addPlugin(litPlugin, {
@ -54,8 +57,16 @@ module.exports = function (eleventyConfig) {
// install filters
filterSort(eleventyConfig);
filterToc(eleventyConfig);
mdMarkdown(eleventyConfig, [
['../theming/README.md', '/theming/material-theming/'],
['./list', '/components/list'],
[/theming\/README/, '/theming/'],
[/^typography\.md/, '/theming/typography/'],
[/^color\.md/, '/theming/color/'],
[/^color\.md/, '/theming/color/'],
[/^components\//, '/components/button/'],
]);
// install transforms
minifyHTML(eleventyConfig, DEV);

View File

@ -18,7 +18,7 @@
"build:prod": "wireit",
"build:prod:eleventy": "wireit",
"build:prod:ts": "wireit",
"build:copy-readmes": "wireit",
"build:copy-docs": "wireit",
"build:copy-stories": "wireit"
},
"wireit": {
@ -43,7 +43,7 @@
],
"dependencies": [
"build:dev:ts",
"build:copy-readmes",
"build:copy-docs",
"build:copy-stories"
]
},
@ -96,7 +96,7 @@
],
"dependencies": [
"build:prod:ts",
"build:copy-readmes",
"build:copy-docs",
"build:copy-stories"
]
},
@ -114,15 +114,22 @@
"..:build"
]
},
"build:copy-readmes": {
"command": "node scripts/copy-readmes.mjs",
"build:copy-docs": {
"command": "node scripts/copy-docs.mjs",
"files": [
"../docs/components",
"scripts/copy-readmes.mjs"
"../docs/theming",
"../docs/*.md",
"../docs/images/",
"scripts/copy-docs.mjs"
],
"output": [
"site/components/**/*.md",
"site/components/images"
"site/components/images",
"site/theming/**/*.md",
"site/theming/images",
"site/about/**/*.md",
"site/about/images"
]
},
"serve:dev": {
@ -179,6 +186,7 @@
"@luncheon/esbuild-plugin-gzip": "^0.1.0",
"@web/dev-server": "^0.1.35",
"@webcomponents/template-shadowroot": "^0.2.1",
"cheerio": "^1.0.0-rc.12",
"clean-css": "^5.3.1",
"eleventy-plugin-compress": "^1.0.5",
"eleventy-plugin-nesting-toc": "^1.3.0",

View File

@ -4,8 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
import {cp, readFile, writeFile} from 'fs/promises';
import {dirname, join, relative} from 'path';
import { cp, readFile, writeFile } from 'fs/promises';
import { dirname, join, relative } from 'path';
import tinyGlob from 'tiny-glob';
/**
@ -15,12 +15,16 @@ import tinyGlob from 'tiny-glob';
* to
* /catalog/site/components/images
*/
async function copyImages() {
await cp(
join('..', 'docs', 'components', 'images'),
join('site', 'components', 'images'), {recursive: true}, (err) => {
if (err) throw err;
});
async function copyImages(path = '', includePath = '') {
const origin = join('..', 'docs', path, 'images');
const desination = join('site', path, includePath, 'images');
console.log(`Copying images from ${origin} to ${desination}...`);
await cp(origin, desination, { recursive: true }, (err) => {
if (err) throw err;
});
console.log(`Copied images from ${origin} to ${desination}!`);
}
/**
@ -29,8 +33,8 @@ async function copyImages() {
*
* @return A promise of all the markdwon filepaths in /docs/components/
*/
async function getReadmeFiles() {
const readmeFilesGlob = ['../docs/components/**/*.md'];
async function getReadmeFiles(path = '', deep = false) {
const readmeFilesGlob = [join('../docs', path, deep ? '/**/' : '', '*.md')];
const readmeFiles = readmeFilesGlob.map(async (entry) => tinyGlob(entry));
return (await Promise.all(readmeFiles)).flat();
}
@ -51,8 +55,7 @@ const transforms = [
// removes everything in between github-only-start and github-only-end
// comments
{
before:
/\s*<!-- no-catalog-start -->(.|\n)*?<!-- no-catalog-end -->\s*/gm,
before: /\s*<!-- no-catalog-start -->(.|\n)*?<!-- no-catalog-end -->\s*/gm,
after: '\n\n',
},
// eleventy pages end with `/` so `components/checkbox.md` will turn into the
@ -97,8 +100,10 @@ async function fileIncludeTransform(filepath, fileContents) {
console.log(`Injecting ${includePath} file contents into ${filepath}...`);
const includeContents = await readFile(join(fileDir, includePath), 'utf8');
fileContents = fileContents.slice(0, match.index) + includeContents +
fileContents.slice(match.index + matchedString.length);
fileContents =
fileContents.slice(0, match.index) +
includeContents +
fileContents.slice(match.index + matchedString.length);
}
return fileContents;
@ -109,8 +114,9 @@ async function fileIncludeTransform(filepath, fileContents) {
* result to /catalog/site/components/<component-name>.md
*
* @param {Array<string>} filepaths The readme file paths to transform.
* @param {[string|RegExp, string|(match: string, ...patterns: string[])][]} replacements File path transforms to apply to output.
*/
async function transformReadmes(filepaths) {
async function transformReadmes(filepaths, outdir = '', replacements = []) {
const readmePromises = filepaths.map(async (entry) => {
let readme = await readFile(entry, 'utf8');
console.log(`Transforming ${entry}`);
@ -122,10 +128,18 @@ async function transformReadmes(filepaths) {
readme = await fileIncludeTransform(entry, readme);
// The `components/<component-name>.md` path.
const localPath = relative(join('..', 'docs'), entry);
let localPath = relative(join('..', 'docs'), entry);
for (const [pattern, replacement] of replacements) {
const regex = new RegExp(pattern);
localPath = localPath.replace(regex, replacement);
}
// The output path at
// /catalog/site/components/<?local path>/<component name>.md
const outputPath = join('site', localPath);
const outputPath = join('site', outdir, localPath);
console.log(`Writing trasnformed file to: ${outputPath}`);
return writeFile(outputPath, readme);
});
@ -133,11 +147,19 @@ async function transformReadmes(filepaths) {
await Promise.all(readmePromises);
}
const readmeFiles = await getReadmeFiles();
const aboutFiles = await getReadmeFiles('.');
const componentsReadmes = await getReadmeFiles('components', true);
const themingFiles = await getReadmeFiles('theming', true);
console.log('Copying images...');
await copyImages();
await copyImages('.', 'about');
await copyImages('components');
await copyImages('theming');
console.log('Images copied!');
console.log('Transforming readmes...');
await transformReadmes(readmeFiles);
await transformReadmes(aboutFiles, 'about');
await transformReadmes(componentsReadmes);
await transformReadmes(themingFiles, '', [
['README', 'material-theming'],
]);
console.log('Transformations complete!');

View File

@ -59,22 +59,45 @@
<main id="main-content" slot="app-content" tabindex="0">
<!-- this is the content of the page -->
<!-- unrelated change to components -->
{% block content %}{{ content | safe }}{% endblock %}
{% block content %}{{ content | mdMarkdown | safe }}{% endblock %}
</main>
<md-list
aria-label="List of pages and components"
role="menubar"
class="nav">
{% for component in collections.component|filtersort('data.name') %}
<md-list-item
href="{{ component.url }}"
role="menuitem"
{% if component.url == page.url %}selected{% endif %}
type="link"
tabindex="{% if component.url == page.url %}0{% else %}-1{% endif %}"
>{{ component.data.name }}</md-list-item>
{% endfor %}
</md-list>
<md-list
aria-label="List of pages and components"
role="menubar"
class="nav">
<md-item>About:</md-item>
{% for file in collections.about|filtersort('data.order') %}
<md-list-item
href="{{ file.url }}"
role="menuitem"
{% if file.url == page.url %}selected{% endif %}
type="link"
tabindex="{% if file.url == page.url %}0{% else %}-1{% endif %}"
>{{ file.data.name }}</md-list-item>
{% endfor %}
<md-divider role="separator"></md-divider>
<md-item>Theming:</md-item>
{% for file in collections.theming|filtersort('data.order') %}
<md-list-item
href="{{ file.url }}"
type="menuitem"
{% if file.url == page.url %}selected{% endif %}
type="link"
tabindex="{% if file.url == page.url %}0{% else %}-1{% endif %}"
>{{ file.data.name }}</md-list-item>
{% endfor %}
<md-divider role="separator"></md-divider>
<md-item>Components:</md-item>
{% for file in collections.component|filtersort('data.name') %}
<md-list-item
href="{{ file.url }}"
role="menuitem"
{% if file.url == page.url %}selected{% endif %}
type="link"
tabindex="{% if file.url == page.url %}0{% else %}-1{% endif %}"
>{{ file.data.name }}</md-list-item>
{% endfor %}
</md-list>
</nav-drawer>
</lit-island>
</body>

View File

@ -2,7 +2,7 @@
{% block head %}
<script type="module" src="/js/pages/components.js"></script>
<link rel="stylesheet" href="/css/components.css" />
<link rel="stylesheet" href="/css/md-layout.css" />
<link rel="stylesheet" href="/css/syntax-highlight.css" />
{% endblock %}
@ -18,5 +18,5 @@
import="/js/hydration-entrypoints{{ page.filePathStem }}.js">
</lit-island>
{% endif %}
{{ content | safe }}
{{ content | mdMarkdown | safe }}
{% endblock %}

View File

@ -0,0 +1,14 @@
{% extends 'default.html' %}
{% block head %}
<link rel="stylesheet" href="/css/md-layout.css" />
<link rel="stylesheet" href="/css/syntax-highlight.css" />
{% endblock %}
{% block toc%}
{{ content | toc | filterToc | safe }}
{% endblock %}
{% block content %}
{{ content | mdMarkdown | safe }}
{% endblock %}

View File

@ -0,0 +1,7 @@
{
"layout": "layouts/docs.html",
"tags": [
"about"
],
"hasToc": true
}

View File

@ -119,8 +119,17 @@ nav-drawer md-list.nav md-list-item[href] {
border-radius: var(--catalog-shape-xl);
}
nav-drawer md-list.nav md-list-item[href]:first-of-type {
margin-block: 4px;
nav-drawer md-list.nav md-item:first-of-type {
padding-block: 0;
}
nav-drawer md-list.nav md-item {
font-size: var(--catalog-headline-s-font-size);
padding-block-end: 0;
}
nav-drawer md-list.nav md-item + md-list-item[href] {
margin-block-start: 0;
}
h1 {

View File

@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
:root {
:root {
--catalog-image-border-radius: 22px;
}
@ -34,6 +34,11 @@ main > * {
max-width: 1760px;
}
main > p img,
main > img {
max-width: 100%;
}
img:not(figure *),
figure {
border-radius: var(--catalog-image-border-radius);
@ -195,9 +200,43 @@ a .offscreen {
blockquote {
margin: var(--catalog-spacing-l);
}
main > blockquote:not(catalog-component-header, details) {
padding: var(--catalog-spacing-l);
border-radius: var(--catalog-shape-l);
background-color: var(--md-sys-color-secondary-container);
display: flex;
gap: var(--catalog-spacing-s);
}
main > blockquote:not(catalog-component-header, details) .content {
flex-grow: 1;
}
blockquote .content > *:first-child {
margin-block-start: 0;
}
blockquote .content > *:last-child {
margin-block-end: 0;
}
blockquote,
blockquote a {
color: var(--md-sys-color-on-secondary-container);
font-style: italic;
}
}
blockquote a {
text-decoration: underline;
font-weight: 700;
}
blockquote.important {
background-color: var(--md-sys-color-primary-container);
}
blockquote.important,
blockquote.important a {
color: var(--md-sys-color-on-primary-container);
}

View File

@ -0,0 +1,7 @@
{
"layout": "layouts/docs.html",
"tags": [
"theming"
],
"hasToc": true
}

View File

@ -79,6 +79,7 @@ export class NavDrawer extends SignalElement(LitElement) {
},
})}
>
<div class="scroll-wrapper">
<slot
${animate({
properties: ['opacity'],
@ -88,6 +89,7 @@ export class NavDrawer extends SignalElement(LitElement) {
},
})}
></slot>
</div>
</aside>
</div>
<div class="panes">
@ -103,8 +105,10 @@ export class NavDrawer extends SignalElement(LitElement) {
class="pane content-pane"
?inert=${showModal || inertContentSignal.value}
>
<div class="content">
<slot name="app-content"></slot>
<div class="scroll-wrapper">
<div class="content">
<slot name="app-content"></slot>
</div>
</div>
</div>`;
}
@ -118,9 +122,11 @@ export class NavDrawer extends SignalElement(LitElement) {
class="pane toc"
?inert=${showModal || inertContentSignal.value}
>
<p>On this page:</p>
<h2>${this.pageTitle}</h2>
<slot name="toc"></slot>
<div class="scroll-wrapper">
<p>On this page:</p>
<h2>${this.pageTitle}</h2>
<slot name="toc"></slot>
</div>
</div>`;
}
@ -150,7 +156,7 @@ export class NavDrawer extends SignalElement(LitElement) {
) {
(
this.querySelector(
'md-list.nav md-list-item[tabindex=0]'
'md-list.nav md-list-item[tabindex="0"]'
) as HTMLElement
)?.focus();
}
@ -200,7 +206,6 @@ export class NavDrawer extends SignalElement(LitElement) {
);
background-color: var(--md-sys-color-surface);
border-radius: var(--catalog-shape-xl);
padding-block: var(--catalog-spacing-xl);
}
.pane,
@ -267,7 +272,18 @@ export class NavDrawer extends SignalElement(LitElement) {
inset: var(--catalog-top-app-bar-height) 0 0 0;
z-index: 12;
background-color: var(--md-sys-color-surface-container);
overflow: hidden;
}
.scroll-wrapper {
overflow-y: auto;
max-height: 100%;
border-radius: inherit;
box-sizing: border-box;
}
.pane .scroll-wrapper {
padding-block: var(--catalog-spacing-xl);
}
aside slot {
@ -356,7 +372,7 @@ export class NavDrawer extends SignalElement(LitElement) {
--_scrollbar-width: 8px;
}
.pane {
.scroll-wrapper {
/* firefox */
scrollbar-color: var(--md-sys-color-primary) transparent;
scrollbar-width: thin;
@ -370,12 +386,12 @@ export class NavDrawer extends SignalElement(LitElement) {
}
/* Chromium + Safari */
.pane::-webkit-scrollbar {
.scroll-wrapper::-webkit-scrollbar {
background-color: transparent;
width: var(--_scrollbar-width);
}
.pane::-webkit-scrollbar-thumb {
.scroll-wrapper::-webkit-scrollbar-thumb {
background-color: var(--md-sys-color-primary);
border-radius: calc(var(--_scrollbar-width) / 2);
}
@ -398,12 +414,12 @@ export class NavDrawer extends SignalElement(LitElement) {
}
@media (pointer: fine) {
.pane {
.scroll-wrapper {
/* firefox */
scrollbar-color: CanvasText transparent;
}
.pane::-webkit-scrollbar-thumb {
.scroll-wrapper::-webkit-scrollbar-thumb {
/* Chromium + Safari */
background-color: CanvasText;
}

View File

@ -155,9 +155,8 @@ export class TopAppBar extends SignalElement(LitElement) {
inset: 0 0 auto 0;
display: flex;
align-items: center;
padding-block-start: var(--catalog-spacing-m);
box-sizing: border-box;
padding: var(--catalog-spacing-m) var(--catalog-spacing-s);
padding: var(--catalog-spacing-m) var(--catalog-spacing-l);
background-color: var(--md-sys-color-surface-container);
color: var(--md-sys-color-on-surface);
z-index: 12;

View File

@ -11,4 +11,5 @@ import './components/catalog-component-header-title.js';
import './components/top-app-bar.js';
import './components/nav-drawer.js';
import './components/theme-changer.js';
import '@material/web/all.js';
import '@material/web/all.js';
import '@material/web/labs/item/item.js';

View File

@ -1,3 +1,9 @@
<!-- catalog-only-start --><!-- ---
name: Intoduction
title: Intoduction
order: 1
-----><!-- catalog-only-end -->
# Intro to Material Web Components
<!-- go/mwc-intro -->

View File

@ -1,3 +1,9 @@
<!-- catalog-only-start --><!-- ---
name: Quick Start
title: Quick Start
order: 2
-----><!-- catalog-only-end -->
# Quick start
<!--*

View File

@ -1,3 +1,9 @@
<!-- catalog-only-start --><!-- ---
name: Roadmap
title: Roadmap
order: 3
-----><!-- catalog-only-end -->
# Roadmap
<!-- go/mwc-roadmap -->

View File

@ -1,3 +1,9 @@
<!-- catalog-only-start --><!-- ---
name: Support
title: Support
order: 4
-----><!-- catalog-only-end -->
# Support
<!-- go/mwc-support -->

View File

@ -1,3 +1,9 @@
<!-- catalog-only-start --><!-- ---
name: Material Theming
title: Theming
order: 1
-----><!-- catalog-only-end -->
# Theming
<!-- go/mwc-theming -->

View File

@ -1,3 +1,9 @@
<!-- catalog-only-start --><!-- ---
name: Color
title: Color
order: 2
-----><!-- catalog-only-end -->
# Color
<!--*

View File

@ -1,3 +1,9 @@
<!-- catalog-only-start --><!-- ---
name: Typography
title: Typography
order: 3
-----><!-- catalog-only-end -->
# Typography
<!-- go/mwc-typography -->

1
package-lock.json generated
View File

@ -51,6 +51,7 @@
"@luncheon/esbuild-plugin-gzip": "^0.1.0",
"@web/dev-server": "^0.1.35",
"@webcomponents/template-shadowroot": "^0.2.1",
"cheerio": "^1.0.0-rc.12",
"clean-css": "^5.3.1",
"eleventy-plugin-compress": "^1.0.5",
"eleventy-plugin-nesting-toc": "^1.3.0",