Rename Markdown util getHeaders()
to getHeadings()
(#4031)
* Renamed getHeaders() to getHeadings(), according to RFC #208. * chore: update changeset * fix: expose MarkdownHeading type from `astro` Co-authored-by: Félix Sanz <me@felixsanz.com> Co-authored-by: Nate Moore <nate@astro.build>
This commit is contained in:
parent
1215e731b8
commit
6e27a5fdc2
12 changed files with 64 additions and 42 deletions
6
.changeset/young-radios-call.md
Normal file
6
.changeset/young-radios-call.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
'astro': patch
|
||||
'@astrojs/markdown-remark': minor
|
||||
---
|
||||
|
||||
**BREAKING** Renamed Markdown utility function `getHeaders()` to `getHeadings()`.
|
|
@ -4,14 +4,14 @@ import TableOfContents from "../RightSidebar/TableOfContents.tsx";
|
|||
|
||||
const { content, githubEditUrl } = Astro.props;
|
||||
const title = content.title;
|
||||
const headers = content.astro.headers;
|
||||
const headings = content.astro.headings;
|
||||
---
|
||||
|
||||
<article id="article" class="content">
|
||||
<section class="main-section">
|
||||
<h1 class="content-title" id="overview">{title}</h1>
|
||||
<nav class="block sm:hidden">
|
||||
<TableOfContents client:media="(max-width: 50em)" {headers} />
|
||||
<TableOfContents client:media="(max-width: 50em)" {headings} />
|
||||
</nav>
|
||||
<slot />
|
||||
</section>
|
||||
|
|
|
@ -8,7 +8,7 @@ const showMoreSection = CONFIG.COMMUNITY_INVITE_URL || editHref;
|
|||
{showMoreSection && <h2 class="heading">More</h2>}
|
||||
<ul>
|
||||
{editHref && (
|
||||
<li class={`header-link depth-2`}>
|
||||
<li class={`heading-link depth-2`}>
|
||||
<a class="edit-on-github" href={editHref} target="_blank">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
|
@ -32,7 +32,7 @@ const showMoreSection = CONFIG.COMMUNITY_INVITE_URL || editHref;
|
|||
</li>
|
||||
)}
|
||||
{CONFIG.COMMUNITY_INVITE_URL && (
|
||||
<li class={`header-link depth-2`}>
|
||||
<li class={`heading-link depth-2`}>
|
||||
<a href={CONFIG.COMMUNITY_INVITE_URL} target="_blank">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
import TableOfContents from "./TableOfContents.tsx";
|
||||
import MoreMenu from "./MoreMenu.astro";
|
||||
const { content, githubEditUrl } = Astro.props;
|
||||
const headers = content.astro.headers;
|
||||
const headings = content.astro.headings;
|
||||
---
|
||||
|
||||
<nav class="sidebar-nav" aria-labelledby="grid-right">
|
||||
<div class="sidebar-nav-inner">
|
||||
<TableOfContents client:media="(min-width: 50em)" {headers} />
|
||||
<TableOfContents client:media="(min-width: 50em)" {headings} />
|
||||
<MoreMenu editHref={githubEditUrl} />
|
||||
</div>
|
||||
</nav>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import type { FunctionalComponent } from 'preact';
|
||||
import { h, Fragment } from 'preact';
|
||||
import { useState, useEffect, useRef } from 'preact/hooks';
|
||||
import { MarkdownHeading } from 'astro';
|
||||
|
||||
const TableOfContents: FunctionalComponent<{ headers: any[] }> = ({ headers = [] }) => {
|
||||
const TableOfContents: FunctionalComponent<{ headings: MarkdownHeading[] }> = ({ headings = [] }) => {
|
||||
const itemOffsets = useRef([]);
|
||||
const [activeId, setActiveId] = useState<string>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
const getItemOffsets = () => {
|
||||
const titles = document.querySelectorAll('article :is(h1, h2, h3, h4)');
|
||||
|
@ -27,18 +27,18 @@ const TableOfContents: FunctionalComponent<{ headers: any[] }> = ({ headers = []
|
|||
<>
|
||||
<h2 class="heading">On this page</h2>
|
||||
<ul>
|
||||
<li class={`header-link depth-2 ${activeId === 'overview' ? 'active' : ''}`.trim()}>
|
||||
<li class={`heading-link depth-2 ${activeId === 'overview' ? 'active' : ''}`.trim()}>
|
||||
<a href="#overview">Overview</a>
|
||||
</li>
|
||||
{headers
|
||||
{headings
|
||||
.filter(({ depth }) => depth > 1 && depth < 4)
|
||||
.map((header) => (
|
||||
.map((heading) => (
|
||||
<li
|
||||
class={`header-link depth-${header.depth} ${
|
||||
activeId === header.slug ? 'active' : ''
|
||||
class={`heading-link depth-${heading.depth} ${
|
||||
activeId === heading.slug ? 'active' : ''
|
||||
}`.trim()}
|
||||
>
|
||||
<a href={`#${header.slug}`}>{header.text}</a>
|
||||
<a href={`#${heading.slug}`}>{heading.text}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
|
|
@ -311,42 +311,42 @@ h2.heading {
|
|||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.header-link {
|
||||
.heading-link {
|
||||
font-size: 1rem;
|
||||
padding: 0.1rem 0 0.1rem 1rem;
|
||||
border-left: 4px solid var(--theme-divider);
|
||||
}
|
||||
|
||||
.header-link:hover,
|
||||
.header-link:focus {
|
||||
.heading-link:hover,
|
||||
.heading-link:focus {
|
||||
border-left-color: var(--theme-accent);
|
||||
color: var(--theme-accent);
|
||||
}
|
||||
.header-link:focus-within {
|
||||
.heading-link:focus-within {
|
||||
color: var(--theme-text-light);
|
||||
border-left-color: hsla(var(--color-gray-40), 1);
|
||||
}
|
||||
.header-link svg {
|
||||
.heading-link svg {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.header-link:hover svg {
|
||||
.heading-link:hover svg {
|
||||
opacity: 0.8;
|
||||
}
|
||||
.header-link a {
|
||||
.heading-link a {
|
||||
display: inline-flex;
|
||||
gap: 0.5em;
|
||||
width: 100%;
|
||||
padding: 0.15em 0 0.15em 0;
|
||||
}
|
||||
|
||||
.header-link.depth-3 {
|
||||
.heading-link.depth-3 {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
.header-link.depth-4 {
|
||||
.heading-link.depth-4 {
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
.header-link a {
|
||||
.heading-link a {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
|
|
4
packages/astro/env.d.ts
vendored
4
packages/astro/env.d.ts
vendored
|
@ -18,7 +18,9 @@ declare module '*.md' {
|
|||
export const frontmatter: MD['frontmatter'];
|
||||
export const file: MD['file'];
|
||||
export const url: MD['url'];
|
||||
export const getHeaders: MD['getHeaders'];
|
||||
export const getHeadings: MD['getHeadings'];
|
||||
/** @deprecated Renamed to `getHeadings()` */
|
||||
export const getHeaders: () => void;
|
||||
export const Content: MD['Content'];
|
||||
export const rawContent: MD['rawContent'];
|
||||
export const compiledContent: MD['compiledContent'];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type {
|
||||
MarkdownHeader,
|
||||
MarkdownHeading,
|
||||
MarkdownMetadata,
|
||||
MarkdownRenderingResult,
|
||||
RehypePlugins,
|
||||
|
@ -16,6 +16,14 @@ import type { AstroConfigSchema } from '../core/config';
|
|||
import type { ViteConfigWithSSR } from '../core/create-vite';
|
||||
import type { AstroComponentFactory, Metadata } from '../runtime/server';
|
||||
export type { SSRManifest } from '../core/app/types';
|
||||
export type {
|
||||
MarkdownHeading,
|
||||
MarkdownMetadata,
|
||||
MarkdownRenderingResult,
|
||||
RehypePlugins,
|
||||
RemarkPlugins,
|
||||
ShikiConfig,
|
||||
} from '@astrojs/markdown-remark';
|
||||
|
||||
export interface AstroBuiltinProps {
|
||||
'client:load'?: boolean;
|
||||
|
@ -783,7 +791,9 @@ export interface MarkdownInstance<T extends Record<string, any>> {
|
|||
rawContent(): string;
|
||||
/** Markdown file compiled to valid Astro syntax. Queryable with most HTML parsing libraries */
|
||||
compiledContent(): Promise<string>;
|
||||
getHeaders(): Promise<MarkdownHeader[]>;
|
||||
getHeadings(): Promise<MarkdownHeading[]>;
|
||||
/** @deprecated Renamed to `getHeadings()` */
|
||||
getHeaders(): void;
|
||||
default: () => Promise<{
|
||||
metadata: MarkdownMetadata;
|
||||
frontmatter: MarkdownContent<T>;
|
||||
|
|
|
@ -123,8 +123,12 @@ export default function markdown({ config }: AstroPluginOptions): Plugin {
|
|||
return load().then((m) => m.default(...args));
|
||||
}
|
||||
Content.isAstroComponentFactory = true;
|
||||
export function getHeadings() {
|
||||
return load().then((m) => m.metadata.headings);
|
||||
}
|
||||
export function getHeaders() {
|
||||
return load().then((m) => m.metadata.headers);
|
||||
console.warn('getHeaders() have been deprecated. Use getHeadings() function instead.');
|
||||
return load().then((m) => m.metadata.headings);
|
||||
};`,
|
||||
map: null,
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { MarkdownRenderingOptions, MarkdownRenderingResult } from './types';
|
||||
|
||||
import { loadPlugins } from './load-plugins.js';
|
||||
import createCollectHeaders from './rehype-collect-headers.js';
|
||||
import createCollectHeadings from './rehype-collect-headings.js';
|
||||
import rehypeEscape from './rehype-escape.js';
|
||||
import rehypeExpressions from './rehype-expressions.js';
|
||||
import rehypeIslands from './rehype-islands.js';
|
||||
|
@ -41,7 +41,7 @@ export async function renderMarkdown(
|
|||
} = opts;
|
||||
const input = new VFile({ value: content, path: fileURL });
|
||||
const scopedClassName = opts.$?.scopedClassName;
|
||||
const { headers, rehypeCollectHeaders } = createCollectHeaders();
|
||||
const { headings, rehypeCollectHeadings } = createCollectHeadings();
|
||||
|
||||
let parser = unified()
|
||||
.use(markdown)
|
||||
|
@ -94,8 +94,8 @@ export async function renderMarkdown(
|
|||
parser
|
||||
.use(
|
||||
isAstroFlavoredMd
|
||||
? [rehypeJsx, rehypeExpressions, rehypeEscape, rehypeIslands, rehypeCollectHeaders]
|
||||
: [rehypeCollectHeaders, rehypeRaw]
|
||||
? [rehypeJsx, rehypeExpressions, rehypeEscape, rehypeIslands, rehypeCollectHeadings]
|
||||
: [rehypeCollectHeadings, rehypeRaw]
|
||||
)
|
||||
.use(rehypeStringify, { allowDangerousHtml: true });
|
||||
|
||||
|
@ -113,7 +113,7 @@ export async function renderMarkdown(
|
|||
}
|
||||
|
||||
return {
|
||||
metadata: { headers, source: content, html: result.toString() },
|
||||
metadata: { headings, source: content, html: result.toString() },
|
||||
code: result.toString(),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,13 +2,13 @@ import Slugger from 'github-slugger';
|
|||
import { toHtml } from 'hast-util-to-html';
|
||||
import { visit } from 'unist-util-visit';
|
||||
|
||||
import type { MarkdownHeader, RehypePlugin } from './types.js';
|
||||
import type { MarkdownHeading, RehypePlugin } from './types.js';
|
||||
|
||||
export default function createCollectHeaders() {
|
||||
const headers: MarkdownHeader[] = [];
|
||||
export default function createCollectHeadings() {
|
||||
const headings: MarkdownHeading[] = [];
|
||||
const slugger = new Slugger();
|
||||
|
||||
function rehypeCollectHeaders(): ReturnType<RehypePlugin> {
|
||||
function rehypeCollectHeadings(): ReturnType<RehypePlugin> {
|
||||
return function (tree) {
|
||||
visit(tree, (node) => {
|
||||
if (node.type !== 'element') return;
|
||||
|
@ -61,13 +61,13 @@ export default function createCollectHeaders() {
|
|||
}
|
||||
}
|
||||
|
||||
headers.push({ depth, slug: node.properties.id, text });
|
||||
headings.push({ depth, slug: node.properties.id, text });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
headers,
|
||||
rehypeCollectHeaders,
|
||||
headings,
|
||||
rehypeCollectHeadings,
|
||||
};
|
||||
}
|
|
@ -44,14 +44,14 @@ export interface MarkdownRenderingOptions extends AstroMarkdownOptions {
|
|||
isAstroFlavoredMd?: boolean;
|
||||
}
|
||||
|
||||
export interface MarkdownHeader {
|
||||
export interface MarkdownHeading {
|
||||
depth: number;
|
||||
slug: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface MarkdownMetadata {
|
||||
headers: MarkdownHeader[];
|
||||
headings: MarkdownHeading[];
|
||||
source: string;
|
||||
html: string;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue