diff --git a/client/storybook/TemplatePattern.tsx b/client/storybook/TemplatePattern.tsx deleted file mode 100644 index 4ef79145b0..0000000000 --- a/client/storybook/TemplatePattern.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React, { useRef, useEffect } from 'react'; - -import { renderPattern, simulateLoading } from 'storybook-django'; - -const getTemplateName = (template?: string, filename?: string): string => - template || - filename?.replace(/.+\/templates\//, '').replace(/\.stories\..+$/, '.html') || - 'template-not-found'; - -type ContextMapping = { [key: string]: any }; -type TagsMapping = { [key: string]: any }; - -interface TemplatePatternProps { - element?: 'div' | 'span'; - // Path to the template file. - template?: string; - // Path to a Storybook `stories` file, which should be placed next to and named the same as the HTML template. - filename?: string; - context?: ContextMapping; - tags?: TagsMapping; -} - -const PATTERN_LIBRARY_RENDER_URL = '/pattern-library/api/v1/render-pattern'; - -/** - * Retrieves a template pattern’s HTML (or error response) from the server. - */ -export const getTemplatePattern = ( - templateName: string, - context: ContextMapping, - tags: TagsMapping, - callback: (html: string) => void, -) => - renderPattern(PATTERN_LIBRARY_RENDER_URL, templateName, context, tags) - .catch(callback) - .then((res) => res.text()) - .then(callback); - -/** - * Renders one of our Django templates as if it was a React component. - * All props are marked as optional, but either template or filename should be provided. - */ -const TemplatePattern = ({ - element = 'div', - template, - filename, - context = {}, - tags = {}, -}: TemplatePatternProps) => { - const ref = useRef(null); - - useEffect(() => { - const templateName = getTemplateName(template, filename); - getTemplatePattern(templateName, context, tags, (html) => - simulateLoading(ref.current, html), - ); - }); - - return React.createElement(element, { ref }); -}; - -export default TemplatePattern; diff --git a/client/storybook/preview.js b/client/storybook/preview.js index 6229254c44..36f6d4b576 100644 --- a/client/storybook/preview.js +++ b/client/storybook/preview.js @@ -29,7 +29,7 @@ const loadIconSprite = () => { const sprite = document.createElement('div'); sprite.innerHTML = html; const symbols = Array.from(sprite.querySelectorAll('symbol')); - const icons = symbols.map((elt) => elt.id.replace('icon-', '')); + const icons = symbols.map((elt) => elt.id.replace('icon-', '')).sort(); window.WAGTAIL_ICONS = icons; sessionStorage.setItem('WAGTAIL_ICONS', JSON.stringify(icons)); diff --git a/package-lock.json b/package-lock.json index 79767355f2..a82c161cbf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "redux-mock-store": "^1.3.0", "sass": "^1.45.1", "sass-loader": "^12.4.0", - "storybook-django": "^0.3.0", + "storybook-django": "^0.5.1", "stylelint": "^14.2.0", "tailwindcss": "^3.0.23", "tailwindcss-vanilla-rtl": "^0.1.0", @@ -26381,12 +26381,20 @@ "dev": true }, "node_modules/storybook-django": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/storybook-django/-/storybook-django-0.3.0.tgz", - "integrity": "sha512-sgepkbrPtbfoCOP9C1yysqyd/ZfrHBdpyBoXgd1oT3qjEtbqDPcXueRATMXY82wJq89tTJgMuGl24dv4JC9l9w==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/storybook-django/-/storybook-django-0.5.1.tgz", + "integrity": "sha512-aanBh2hU/ucP+0zjfAsAvFZtwY/e07FWgTzTjb1fKUpCeliutrrzkaH/9veVccZtr2zSqD3M1xgRLhN/YsQ0iA==", "dev": true, "dependencies": { "http-proxy-middleware": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } } }, "node_modules/stream-browserify": { @@ -50028,9 +50036,9 @@ "dev": true }, "storybook-django": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/storybook-django/-/storybook-django-0.3.0.tgz", - "integrity": "sha512-sgepkbrPtbfoCOP9C1yysqyd/ZfrHBdpyBoXgd1oT3qjEtbqDPcXueRATMXY82wJq89tTJgMuGl24dv4JC9l9w==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/storybook-django/-/storybook-django-0.5.1.tgz", + "integrity": "sha512-aanBh2hU/ucP+0zjfAsAvFZtwY/e07FWgTzTjb1fKUpCeliutrrzkaH/9veVccZtr2zSqD3M1xgRLhN/YsQ0iA==", "dev": true, "requires": { "http-proxy-middleware": "^2.0.0" diff --git a/package.json b/package.json index 7f7baff560..aa5f53a5d5 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "redux-mock-store": "^1.3.0", "sass": "^1.45.1", "sass-loader": "^12.4.0", - "storybook-django": "^0.3.0", + "storybook-django": "^0.5.1", "stylelint": "^14.2.0", "tailwindcss": "^3.0.23", "tailwindcss-vanilla-rtl": "^0.1.0", diff --git a/wagtail/admin/templates/wagtailadmin/shared/breadcrumb.html b/wagtail/admin/templates/wagtailadmin/shared/breadcrumb.html index 977c360ebd..f32c424e49 100644 --- a/wagtail/admin/templates/wagtailadmin/shared/breadcrumb.html +++ b/wagtail/admin/templates/wagtailadmin/shared/breadcrumb.html @@ -1,4 +1,7 @@ {% load i18n wagtailadmin_tags %} +{% comment "text/markdown" %} + The breadcrumb component is reused across a lot of Wagtail’s headers. +{% endcomment %} {% if use_next_template %} {% include 'wagtailadmin/shared/breadcrumb-next.html' with trailing_breadcrumb_title=trailing_breadcrumb_title %} diff --git a/wagtail/admin/templates/wagtailadmin/shared/breadcrumb.md b/wagtail/admin/templates/wagtailadmin/shared/breadcrumb.md deleted file mode 100644 index c81cbee078..0000000000 --- a/wagtail/admin/templates/wagtailadmin/shared/breadcrumb.md +++ /dev/null @@ -1 +0,0 @@ -The breadcrumb component is reused across a lot of Wagtail’s headers. diff --git a/wagtail/admin/templates/wagtailadmin/shared/breadcrumb.stories.tsx b/wagtail/admin/templates/wagtailadmin/shared/breadcrumb.stories.tsx index df526ace60..b1bbaf7c97 100644 --- a/wagtail/admin/templates/wagtailadmin/shared/breadcrumb.stories.tsx +++ b/wagtail/admin/templates/wagtailadmin/shared/breadcrumb.stories.tsx @@ -1,21 +1,15 @@ import React from 'react'; -import TemplatePattern from '../../../../../client/storybook/TemplatePattern'; +import { Pattern, generateDocs } from 'storybook-django/src/react'; import template from './breadcrumb.html'; -import docs from './breadcrumb.md'; + +const { docs } = generateDocs(template); export default { - parameters: { - docs: { - source: { code: template }, - extractComponentDescription: () => docs, - }, - }, + parameters: { docs }, }; -const Template = (args) => ( - -); +const Template = (args) => ; export const Base = Template.bind({}); diff --git a/wagtail/admin/templates/wagtailadmin/shared/header.html b/wagtail/admin/templates/wagtailadmin/shared/header.html index 8957cb3cfb..ae987152db 100644 --- a/wagtail/admin/templates/wagtailadmin/shared/header.html +++ b/wagtail/admin/templates/wagtailadmin/shared/header.html @@ -1,10 +1,10 @@ {% load i18n wagtailadmin_tags %} -{% comment %} +{% comment "text/markdown" %} Variables accepted by this template: - - `title` - - `subtitle` + - `title` - Displayed as `h1` + - `subtitle` - Within the `h1` tag but smaller - `search_url` - if present, display a search box. This is a URL route name (taking no parameters) to be used as the action for that search box - `query_parameters` - a query string (without the '?') to be placed after the search URL - `icon` - name of an icon to place against the title diff --git a/wagtail/admin/templates/wagtailadmin/shared/header.stories.tsx b/wagtail/admin/templates/wagtailadmin/shared/header.stories.tsx index 1860afd3db..6b499edd48 100644 --- a/wagtail/admin/templates/wagtailadmin/shared/header.stories.tsx +++ b/wagtail/admin/templates/wagtailadmin/shared/header.stories.tsx @@ -1,20 +1,16 @@ import React from 'react'; -import TemplatePattern from '../../../../../client/storybook/TemplatePattern'; +import { Pattern, generateDocs } from 'storybook-django/src/react'; import template from './header.html'; +const { docs, argTypes } = generateDocs(template); + export default { parameters: { - docs: { - source: { code: template }, - // Trial generating documentation from comment within the template. To be replaced by a better pattern. - extractComponentDescription: () => - template - .match(/{% comment %}\n((.|\n)+){% endcomment %}/m)[1] - .replace(/ {4}/g, ''), - }, + docs, }, argTypes: { + ...argTypes, icon: { options: window.WAGTAIL_ICONS, control: { type: 'select' }, @@ -23,9 +19,7 @@ export default { }, }; -const Template = (args) => ( - -); +const Template = (args) => ; export const Base = Template.bind({}); diff --git a/wagtail/admin/templates/wagtailadmin/shared/icons.stories.tsx b/wagtail/admin/templates/wagtailadmin/shared/icons.stories.tsx index 982154c5a2..c5837762d7 100644 --- a/wagtail/admin/templates/wagtailadmin/shared/icons.stories.tsx +++ b/wagtail/admin/templates/wagtailadmin/shared/icons.stories.tsx @@ -1,10 +1,10 @@ import React, { useState, useEffect } from 'react'; -import { getTemplatePattern } from '../../../../../client/storybook/TemplatePattern'; +import { getTemplatePattern } from 'storybook-django/src/react'; /** * Displays all icons within our sprite. */ -const Icons = ({ color }: { color: string }) => { +const IconsTable = ({ color }: { color: string }) => { const [template, setTemplate] = useState(''); useEffect(() => { @@ -17,20 +17,33 @@ const Icons = ({ color }: { color: string }) => { }, []); return ( - <> + + All registered icons + + + Visual + Name + Usage + + {window.WAGTAIL_ICONS.map((icon) => ( - - + - {`{% icon name="${icon}" %}`} - + + {icon} + + + {`{% icon name="${icon}" %}`} + + ))} - > + ); }; @@ -42,8 +55,8 @@ export default { }, }; -export const icons = (args) => ; +export const Icons = (args) => ; -icons.args = { +Icons.args = { color: 'currentColor', };
{`{% icon name="${icon}" %}`}
{icon}