fix(cms): enable the Tailwind typography plugin so prose classes work (#1288)
tailwind.config.js had plugins: [] and @tailwindcss/typography was never
installed, so every prose / prose-neutral / dark:prose-invert class in the
app resolved to nothing. Preflight, which IS active, resets h1-h6 to
inherit size and weight and strips list-style from ul/ol — so an applied
<h2> rendered pixel-identical to the <p> it replaced.
The editor was never broken. The toolbar highlighted because
editor.isActive('heading') correctly returned true; only the CSS to show
it was missing. That also explains why pasting rendered rich text worked:
it carries inline styles.
Ten surfaces rely on these classes, including the PUBLIC CMS pages — so
impressum/datenschutz were serving unstyled headings to visitors too.
Review follow-ups: prose colours are mapped to the theme tokens wherever
.text-theme marks theme-owned text (a dark gallery preset sets
--color-text but no .dark class, so dark:prose-invert never engages and
headings would have gone near-black on dark); code blocks inherit rather
than being scaled twice; and H5/H6 get explicit rules, since the plugin
only styles h1-h4.
Closes #1288
This commit is contained in:
Generated
+31
-3
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "picpeak-frontend",
|
"name": "picpeak-frontend",
|
||||||
"version": "3.122.5-beta.0",
|
"version": "3.122.6-beta.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "picpeak-frontend",
|
"name": "picpeak-frontend",
|
||||||
"version": "3.122.5-beta.0",
|
"version": "3.122.6-beta.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dagrejs/dagre": "^3.0.0",
|
"@dagrejs/dagre": "^3.0.0",
|
||||||
"@fullcalendar/core": "^6.1.20",
|
"@fullcalendar/core": "^6.1.20",
|
||||||
@@ -59,6 +59,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.29.0",
|
"@eslint/js": "^9.29.0",
|
||||||
|
"@tailwindcss/typography": "^0.5.20",
|
||||||
"@testing-library/jest-dom": "^6.6.3",
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
"@testing-library/react": "^16.1.0",
|
"@testing-library/react": "^16.1.0",
|
||||||
"@testing-library/user-event": "^14.6.1",
|
"@testing-library/user-event": "^14.6.1",
|
||||||
@@ -2843,6 +2844,33 @@
|
|||||||
"@swc/counter": "^0.1.3"
|
"@swc/counter": "^0.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tailwindcss/typography": {
|
||||||
|
"version": "0.5.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.20.tgz",
|
||||||
|
"integrity": "sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"postcss-selector-parser": "6.0.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"tailwindcss": ">=3.0.0 || >=4.0.0 || insiders"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": {
|
||||||
|
"version": "6.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
|
||||||
|
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cssesc": "^3.0.0",
|
||||||
|
"util-deprecate": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tanstack/query-core": {
|
"node_modules/@tanstack/query-core": {
|
||||||
"version": "5.90.16",
|
"version": "5.90.16",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.16.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.16.tgz",
|
||||||
@@ -7592,7 +7620,6 @@
|
|||||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -8843,6 +8870,7 @@
|
|||||||
"integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==",
|
"integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.29.0",
|
"@eslint/js": "^9.29.0",
|
||||||
|
"@tailwindcss/typography": "^0.5.20",
|
||||||
"@testing-library/jest-dom": "^6.6.3",
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
"@testing-library/react": "^16.1.0",
|
"@testing-library/react": "^16.1.0",
|
||||||
"@testing-library/user-event": "^14.6.1",
|
"@testing-library/user-event": "^14.6.1",
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* The `prose` classes must actually resolve to CSS (#1288).
|
||||||
|
*
|
||||||
|
* Tailwind's Preflight resets h1-h6 to inherit size and weight, and strips
|
||||||
|
* list-style and padding from ul/ol. Ten places in this app render rich text
|
||||||
|
* in a `prose` container and depend on @tailwindcss/typography to put that
|
||||||
|
* back. With the plugin missing, every `prose*` class is a no-op — so applying
|
||||||
|
* a heading or a list in the CMS editor changed the document and changed
|
||||||
|
* nothing on screen. The toolbar button lit up (the editor state was right)
|
||||||
|
* while the text stayed visually a paragraph, which is why it read as "the
|
||||||
|
* formatting buttons do nothing".
|
||||||
|
*
|
||||||
|
* A missing plugin produces no error and no warning — the class simply does
|
||||||
|
* not exist — so a config guard is the only cheap place to notice.
|
||||||
|
*/
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { readFileSync } from 'fs';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
|
||||||
|
const root = resolve(__dirname, '../..');
|
||||||
|
|
||||||
|
describe('tailwind typography plugin (#1288)', () => {
|
||||||
|
const config = readFileSync(resolve(root, 'tailwind.config.js'), 'utf8');
|
||||||
|
|
||||||
|
it('is registered in the tailwind config', () => {
|
||||||
|
expect(config).toMatch(/require\(['"]@tailwindcss\/typography['"]\)/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is a declared dependency', () => {
|
||||||
|
const pkg = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'));
|
||||||
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
||||||
|
expect(deps['@tailwindcss/typography']).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('actually resolves, rather than just being named in the config', async () => {
|
||||||
|
const plugin = await import('@tailwindcss/typography');
|
||||||
|
expect(plugin.default).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('theme-owned prose colours', () => {
|
||||||
|
const overrides = readFileSync(resolve(root, 'src/styles/prose-overrides.css'), 'utf8');
|
||||||
|
|
||||||
|
// The plugin ships a fixed near-black palette and sets `color` on the
|
||||||
|
// heading ELEMENT, which beats the container's inherited colour. A dark
|
||||||
|
// gallery preset writes a near-white --color-text on :root and does NOT
|
||||||
|
// add a `.dark` class, so `dark:prose-invert` never engages — without
|
||||||
|
// this mapping the promo block, info banner and public CMS pages render
|
||||||
|
// near-black headings on a dark background.
|
||||||
|
it('remaps the prose palette wherever the theme owns the text colour', () => {
|
||||||
|
expect(overrides).toMatch(/\.prose\.text-theme\s*\{/);
|
||||||
|
expect(overrides).toMatch(/--tw-prose-headings:\s*var\(--color-text\)/);
|
||||||
|
expect(overrides).toMatch(/--tw-prose-body:\s*var\(--color-text\)/);
|
||||||
|
expect(overrides).toMatch(/--tw-prose-bold:\s*var\(--color-text\)/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps the gallery prose surfaces carrying the text-theme marker', () => {
|
||||||
|
// The mapping is keyed on that class; a consumer that drops it silently
|
||||||
|
// falls back to the near-black palette.
|
||||||
|
for (const file of [
|
||||||
|
'src/components/gallery/GalleryLayout.tsx',
|
||||||
|
'src/components/common/CMSContentBlock.tsx',
|
||||||
|
]) {
|
||||||
|
const src = readFileSync(resolve(root, file), 'utf8');
|
||||||
|
const proseLines = src.split('\n').filter((l) => /className|class=/.test(l) && /\bprose\b/.test(l));
|
||||||
|
expect(proseLines.length).toBeGreaterThan(0);
|
||||||
|
for (const line of proseLines) {
|
||||||
|
expect(line).toMatch(/text-theme/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -107,7 +107,7 @@ export const CMSContentBlock: React.FC<CMSContentBlockProps> = ({ slug, fallback
|
|||||||
{page.title}
|
{page.title}
|
||||||
</h1>
|
</h1>
|
||||||
<div
|
<div
|
||||||
className="prose prose-neutral dark:prose-invert max-w-none"
|
className="prose prose-neutral dark:prose-invert max-w-none text-theme"
|
||||||
style={{ color: 'var(--color-text)' }}
|
style={{ color: 'var(--color-text)' }}
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: DOMPurify.sanitize(page.content, {
|
__html: DOMPurify.sanitize(page.content, {
|
||||||
|
|||||||
@@ -562,7 +562,7 @@ export const BrandingPage: React.FC = () => {
|
|||||||
will see (#482). */}
|
will see (#482). */}
|
||||||
<MarkdownContent
|
<MarkdownContent
|
||||||
source={brandingSettings.promo_markdown}
|
source={brandingSettings.promo_markdown}
|
||||||
className={`text-sm text-neutral-800 dark:text-neutral-200 prose prose-sm prose-a:text-primary-600 dark:prose-a:text-primary-400 ${
|
className={`text-sm text-neutral-800 dark:text-neutral-200 prose prose-sm dark:prose-invert max-w-none prose-a:text-primary-600 dark:prose-a:text-primary-400 ${
|
||||||
brandingSettings.promo_alignment === 'left' ? 'text-left'
|
brandingSettings.promo_alignment === 'left' ? 'text-left'
|
||||||
: brandingSettings.promo_alignment === 'right' ? 'text-right'
|
: brandingSettings.promo_alignment === 'right' ? 'text-right'
|
||||||
: 'text-center'
|
: 'text-center'
|
||||||
@@ -610,7 +610,7 @@ export const BrandingPage: React.FC = () => {
|
|||||||
classes — so the admin sees what guests will see. */}
|
classes — so the admin sees what guests will see. */}
|
||||||
<MarkdownContent
|
<MarkdownContent
|
||||||
source={brandingSettings.info_markdown}
|
source={brandingSettings.info_markdown}
|
||||||
className="text-sm text-neutral-800 dark:text-neutral-200 prose prose-sm prose-a:text-primary-600 dark:prose-a:text-primary-400 text-center"
|
className="text-sm text-neutral-800 dark:text-neutral-200 prose prose-sm dark:prose-invert max-w-none prose-a:text-primary-600 dark:prose-a:text-primary-400 text-center"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -527,7 +527,7 @@ export const EventInformationCard: React.FC<EventInformationCardProps> = ({
|
|||||||
<p className="text-xs uppercase tracking-wide text-neutral-500 dark:text-neutral-400 mb-2">
|
<p className="text-xs uppercase tracking-wide text-neutral-500 dark:text-neutral-400 mb-2">
|
||||||
{t('events.promoBanner.preview', 'Preview')}
|
{t('events.promoBanner.preview', 'Preview')}
|
||||||
</p>
|
</p>
|
||||||
<MarkdownContent source={editForm.promo_markdown} className="text-sm text-neutral-800 dark:text-neutral-200 prose-sm prose-a:text-primary-600 dark:prose-a:text-primary-400" />
|
<MarkdownContent source={editForm.promo_markdown} className="prose prose-sm dark:prose-invert max-w-none text-sm text-neutral-800 dark:text-neutral-200 prose-a:text-primary-600 dark:prose-a:text-primary-400" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -575,7 +575,7 @@ export const EventInformationCard: React.FC<EventInformationCardProps> = ({
|
|||||||
<p className="text-xs uppercase tracking-wide text-neutral-500 dark:text-neutral-400 mb-2">
|
<p className="text-xs uppercase tracking-wide text-neutral-500 dark:text-neutral-400 mb-2">
|
||||||
{t('events.infoBanner.preview', 'Preview')}
|
{t('events.infoBanner.preview', 'Preview')}
|
||||||
</p>
|
</p>
|
||||||
<MarkdownContent source={editForm.info_markdown} className="text-sm text-neutral-800 dark:text-neutral-200 prose-sm prose-a:text-primary-600 dark:prose-a:text-primary-400" />
|
<MarkdownContent source={editForm.info_markdown} className="prose prose-sm dark:prose-invert max-w-none text-sm text-neutral-800 dark:text-neutral-200 prose-a:text-primary-600 dark:prose-a:text-primary-400" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -34,6 +34,16 @@
|
|||||||
*/
|
*/
|
||||||
.prose pre {
|
.prose pre {
|
||||||
background-color: var(--color-elevated, #f5f5f5);
|
background-color: var(--color-elevated, #f5f5f5);
|
||||||
|
/*
|
||||||
|
* The typography plugin sets an explicit `color: var(--tw-prose-pre-code)`
|
||||||
|
* on <pre> — #e5e7eb, chosen for ITS dark default background. This rule
|
||||||
|
* replaces that background with the light `--color-elevated`, which left
|
||||||
|
* near-white text on a near-white block everywhere a code sample appears.
|
||||||
|
* Inheriting instead restores the pre-plugin behaviour and stays correct in
|
||||||
|
* every context: themed prose inherits --color-text, admin prose inherits
|
||||||
|
* the (possibly inverted) prose body colour.
|
||||||
|
*/
|
||||||
|
color: inherit;
|
||||||
border: 1px solid var(--color-surface-border, #e5e5e5);
|
border: 1px solid var(--color-surface-border, #e5e5e5);
|
||||||
border-radius: 0.375rem;
|
border-radius: 0.375rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
@@ -44,7 +54,14 @@
|
|||||||
.prose pre code {
|
.prose pre code {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 0.875em;
|
/*
|
||||||
|
* `inherit`, not a second 0.875em. This rule predates the typography
|
||||||
|
* plugin, which now sizes the <pre> itself to 0.875em (0.857em under
|
||||||
|
* prose-sm) and deliberately leaves its `pre code` at `inherit`. Keeping a
|
||||||
|
* multiplier here scaled block code TWICE — 12.25px in base prose, 10.5px
|
||||||
|
* in prose-sm, against 14px body.
|
||||||
|
*/
|
||||||
|
font-size: inherit;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,3 +125,77 @@
|
|||||||
content: "\200B"; /* Zero-width space */
|
content: "\200B"; /* Zero-width space */
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
* Theme-owned prose colours (#1288 review follow-up)
|
||||||
|
*
|
||||||
|
* Enabling @tailwindcss/typography gave `.prose` its own fixed palette:
|
||||||
|
* `--tw-prose-headings` and `--tw-prose-bold` default to near-black, and the
|
||||||
|
* generated `.prose :where(h1)…` rules set `color` on the ELEMENT, which beats
|
||||||
|
* the container's inherited colour.
|
||||||
|
*
|
||||||
|
* That is wrong on every gallery surface. A dark gallery preset (darkModern
|
||||||
|
* and friends) writes a near-white `--color-text` on :root but deliberately
|
||||||
|
* does NOT add a `.dark` class, so `dark:prose-invert` never engages — and the
|
||||||
|
* promo block, the info banner and public CMS pages would have rendered
|
||||||
|
* near-black headings on a dark background. Readable before this plugin
|
||||||
|
* existed, unreadable after: exactly the regression the plugin was meant to
|
||||||
|
* avoid.
|
||||||
|
*
|
||||||
|
* Keyed on `.text-theme`, which is the app's existing marker for "the active
|
||||||
|
* theme owns the text colour here". Admin surfaces (the CMS and email
|
||||||
|
* editors, the update modal) do not carry it and keep the stock palette,
|
||||||
|
* which is what they want — they sit on fixed neutral chrome and already
|
||||||
|
* handle dark mode through the real `.dark` class.
|
||||||
|
* ------------------------------------------------------------------------ */
|
||||||
|
.prose.text-theme {
|
||||||
|
--tw-prose-body: var(--color-text);
|
||||||
|
--tw-prose-headings: var(--color-text);
|
||||||
|
--tw-prose-lead: var(--color-text);
|
||||||
|
--tw-prose-bold: var(--color-text);
|
||||||
|
--tw-prose-quotes: var(--color-text);
|
||||||
|
--tw-prose-captions: var(--color-muted-text, var(--color-text));
|
||||||
|
--tw-prose-code: var(--color-text);
|
||||||
|
/* Markers and rules are decoration, not text — muted so a bullet list does
|
||||||
|
not read as heavier than the copy beside it. */
|
||||||
|
--tw-prose-bullets: var(--color-muted-text, currentColor);
|
||||||
|
--tw-prose-counters: var(--color-muted-text, currentColor);
|
||||||
|
--tw-prose-hr: var(--color-surface-border, currentColor);
|
||||||
|
--tw-prose-quote-borders: var(--color-surface-border, currentColor);
|
||||||
|
--tw-prose-th-borders: var(--color-surface-border, currentColor);
|
||||||
|
--tw-prose-td-borders: var(--color-surface-border, currentColor);
|
||||||
|
/* The gallery surfaces pass `prose-a:text-accent` explicitly; this keeps a
|
||||||
|
consumer that forgets it from falling back to Tailwind's blue. */
|
||||||
|
--tw-prose-links: var(--color-accent, var(--color-text));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
* H5 and H6 (#1288 review round 2)
|
||||||
|
*
|
||||||
|
* @tailwindcss/typography defines heading typography for h1-h4 only. Preflight
|
||||||
|
* still resets h5 and h6 to inherit size and weight, so those two toolbar
|
||||||
|
* buttons stayed exactly as inert as the four this PR fixed — the same bug,
|
||||||
|
* two levels down.
|
||||||
|
*
|
||||||
|
* Sized to continue the plugin's own scale (h4 is 1em/700) rather than
|
||||||
|
* inventing a new one: h5 slightly under body, h6 smaller and uppercase so it
|
||||||
|
* still reads as a heading at that size.
|
||||||
|
* ------------------------------------------------------------------------ */
|
||||||
|
.prose :where(h5):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
||||||
|
color: var(--tw-prose-headings);
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: 1.6em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose :where(h6):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
||||||
|
color: var(--tw-prose-headings);
|
||||||
|
font-size: 0.85em;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-top: 1.6em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|||||||
@@ -104,6 +104,18 @@ export default {
|
|||||||
...Array.from({ length: 12 }, (_, i) => `lg:grid-cols-${i + 1}`),
|
...Array.from({ length: 12 }, (_, i) => `lg:grid-cols-${i + 1}`),
|
||||||
...Array.from({ length: 12 }, (_, i) => `xl:grid-cols-${i + 1}`),
|
...Array.from({ length: 12 }, (_, i) => `xl:grid-cols-${i + 1}`),
|
||||||
],
|
],
|
||||||
plugins: [],
|
plugins: [
|
||||||
|
// Tailwind's Preflight resets h1-h6 to inherit their size and weight, and
|
||||||
|
// strips list-style and padding from ul/ol. Ten places in this app render
|
||||||
|
// rich text inside a `prose` container and rely on this plugin to put that
|
||||||
|
// typography back — the CMS editor and its preview, the public CMS page,
|
||||||
|
// release notes, and the gallery welcome message among them.
|
||||||
|
//
|
||||||
|
// Without it every `prose*` class is a no-op, so applying a heading or a
|
||||||
|
// list in the CMS editor changed the document and changed NOTHING on
|
||||||
|
// screen: the toolbar button lit up (the editor state was correct) while
|
||||||
|
// the text stayed visually a paragraph. That is issue #1288.
|
||||||
|
require('@tailwindcss/typography'),
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user