feat: Add estimated reading time to DocsHeader and DocsLayout
This commit is contained in:
parent
d0dca7d956
commit
b7ad77d73b
@ -1,19 +1,32 @@
|
|||||||
import { usePageContext } from "vike-react/usePageContext";
|
import { usePageContext } from "vike-react/usePageContext";
|
||||||
|
import { ClockIcon } from "@heroicons/react/24/outline";
|
||||||
import { navigation } from "@/lib/navigation";
|
import { navigation } from "@/lib/navigation";
|
||||||
|
|
||||||
export function DocsHeader({ title }: { title?: string }) {
|
type DocsHeaderProps = {
|
||||||
|
title?: string;
|
||||||
|
estimatedReadingTime?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function DocsHeader(props: DocsHeaderProps) {
|
||||||
const { urlPathname } = usePageContext();
|
const { urlPathname } = usePageContext();
|
||||||
|
|
||||||
const section = navigation.find((section) => section.links.find((link) => link.href === urlPathname));
|
const section = navigation.find((section) => section.links.find((link) => link.href === urlPathname));
|
||||||
|
|
||||||
if (!title && !section) {
|
if (!props.title && !section) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="mb-9 space-y-1">
|
<header className="mb-9 space-y-1">
|
||||||
{section && <p className="font-display text-sm font-medium text-violet-500">{section.title}</p>}
|
{section && <p className="font-display text-sm font-medium text-violet-500">{section.title}</p>}
|
||||||
{title && <h1 className="font-display text-3xl tracking-tight text-slate-900 dark:text-white">{title}</h1>}
|
{props.title && (
|
||||||
|
<h1 className="font-display text-3xl tracking-tight text-slate-900 dark:text-white">{props.title}</h1>
|
||||||
|
)}
|
||||||
|
{props.estimatedReadingTime && (
|
||||||
|
<p className="text-sm text-slate-500 dark:text-slate-400 inline-flex items-center gap-1">
|
||||||
|
<ClockIcon className="w-4" /> {props.estimatedReadingTime}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,10 +9,12 @@ import { Prose } from "@syntax/Prose";
|
|||||||
export function DocsLayout({
|
export function DocsLayout({
|
||||||
children,
|
children,
|
||||||
frontmatter: { title },
|
frontmatter: { title },
|
||||||
|
estimatedReadingTime,
|
||||||
nodes,
|
nodes,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
frontmatter: { title?: string };
|
frontmatter: { title?: string };
|
||||||
|
estimatedReadingTime?: string;
|
||||||
nodes: Array<Node>;
|
nodes: Array<Node>;
|
||||||
}) {
|
}) {
|
||||||
let tableOfContents = collectSections(nodes);
|
let tableOfContents = collectSections(nodes);
|
||||||
@ -21,7 +23,7 @@ export function DocsLayout({
|
|||||||
<>
|
<>
|
||||||
<div className="max-w-2xl min-w-0 flex-auto px-4 py-16 lg:max-w-none lg:pr-0 lg:pl-8 xl:px-16">
|
<div className="max-w-2xl min-w-0 flex-auto px-4 py-16 lg:max-w-none lg:pr-0 lg:pl-8 xl:px-16">
|
||||||
<article>
|
<article>
|
||||||
<DocsHeader title={title} />
|
<DocsHeader title={title} estimatedReadingTime={estimatedReadingTime} />
|
||||||
<Prose>{children}</Prose>
|
<Prose>{children}</Prose>
|
||||||
</article>
|
</article>
|
||||||
<PrevNextLinks />
|
<PrevNextLinks />
|
||||||
|
|||||||
@ -18,6 +18,7 @@ const nodes = {
|
|||||||
this.render,
|
this.render,
|
||||||
{
|
{
|
||||||
frontmatter: yaml.load(node.attributes.frontmatter),
|
frontmatter: yaml.load(node.attributes.frontmatter),
|
||||||
|
estimatedReadingTime: config?.variables?.estimatedReadingTime,
|
||||||
nodes: node.children,
|
nodes: node.children,
|
||||||
},
|
},
|
||||||
node.transformChildren(config),
|
node.transformChildren(config),
|
||||||
@ -12,6 +12,7 @@
|
|||||||
"@fontsource-variable/inter": "^5.2.5",
|
"@fontsource-variable/inter": "^5.2.5",
|
||||||
"@fontsource-variable/lexend": "^5.2.5",
|
"@fontsource-variable/lexend": "^5.2.5",
|
||||||
"@headlessui/react": "^2.2.0",
|
"@headlessui/react": "^2.2.0",
|
||||||
|
"@heroicons/react": "^2.2.0",
|
||||||
"@markdoc/markdoc": "^0.5.1",
|
"@markdoc/markdoc": "^0.5.1",
|
||||||
"@sindresorhus/slugify": "^2.2.1",
|
"@sindresorhus/slugify": "^2.2.1",
|
||||||
"@tailwindcss/typography": "^0.5.16",
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
@ -28,6 +29,7 @@
|
|||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-highlight-words": "^0.21.0",
|
"react-highlight-words": "^0.21.0",
|
||||||
|
"reading-time-estimator": "^1.12.0",
|
||||||
"simple-functional-loader": "^1.2.1",
|
"simple-functional-loader": "^1.2.1",
|
||||||
"telefunc": "^0.1.87",
|
"telefunc": "^0.1.87",
|
||||||
"unplugin-fonts": "^1.3.1",
|
"unplugin-fonts": "^1.3.1",
|
||||||
|
|||||||
@ -7,10 +7,10 @@ import tags from "@/markdoc/tags";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const { doc } = useData<Data>();
|
const { doc, estimatedReadingTime } = useData<Data>();
|
||||||
|
|
||||||
const parsedDoc = Markdoc.parse(doc.content);
|
const parsedDoc = Markdoc.parse(doc.content);
|
||||||
const transformedDoc = Markdoc.transform(parsedDoc, { nodes, tags, variables: {} });
|
const transformedDoc = Markdoc.transform(parsedDoc, { nodes, tags, variables: { estimatedReadingTime } });
|
||||||
|
|
||||||
return Markdoc.renderers.react(transformedDoc, React);
|
return Markdoc.renderers.react(transformedDoc, React);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import type { PageContext } from "vike/types";
|
import type { PageContext } from "vike/types";
|
||||||
|
|
||||||
import { docsService } from "@/services/DocsService";
|
import { docsService } from "@/services/DocsService";
|
||||||
|
import { readingTime } from "reading-time-estimator";
|
||||||
import { useConfig } from "vike-react/useConfig";
|
import { useConfig } from "vike-react/useConfig";
|
||||||
import buildTitle from "@/pages/buildTitle";
|
import buildTitle from "@/pages/buildTitle";
|
||||||
import { render } from "vike/abort";
|
import { render } from "vike/abort";
|
||||||
@ -18,7 +19,7 @@ export async function data(pageContext: PageContext) {
|
|||||||
throw render(404);
|
throw render(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log({ doc });
|
const readingTimeObject = readingTime(doc.content, 300, "fr");
|
||||||
|
|
||||||
config({
|
config({
|
||||||
title: buildTitle(doc.title),
|
title: buildTitle(doc.title),
|
||||||
@ -27,5 +28,5 @@ export async function data(pageContext: PageContext) {
|
|||||||
|
|
||||||
docsService.transform(doc);
|
docsService.transform(doc);
|
||||||
|
|
||||||
return { doc };
|
return { doc, estimatedReadingTime: readingTimeObject.text };
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { useData } from "vike-react/useData";
|
|
||||||
import type { Data } from "./+data.js";
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
const movie = useData<Data>();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h1>{movie.title}</h1>
|
|
||||||
Release Date: {movie.release_date}
|
|
||||||
<br />
|
|
||||||
Director: {movie.director}
|
|
||||||
<br />
|
|
||||||
Producer: {movie.producer}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
// https://vike.dev/data
|
|
||||||
|
|
||||||
import type { PageContextServer } from "vike/types";
|
|
||||||
import type { MovieDetails } from "../types.js";
|
|
||||||
import { useConfig } from "vike-react/useConfig";
|
|
||||||
|
|
||||||
export type Data = Awaited<ReturnType<typeof data>>;
|
|
||||||
|
|
||||||
export const data = async (pageContext: PageContextServer) => {
|
|
||||||
// https://vike.dev/useConfig
|
|
||||||
const config = useConfig();
|
|
||||||
|
|
||||||
const response = await fetch(`https://brillout.github.io/star-wars/api/films/${pageContext.routeParams.id}.json`);
|
|
||||||
let movie = (await response.json()) as MovieDetails;
|
|
||||||
|
|
||||||
config({
|
|
||||||
// Set <title>
|
|
||||||
title: movie.title,
|
|
||||||
});
|
|
||||||
|
|
||||||
// We remove data we don't need because the data is passed to
|
|
||||||
// the client; we should minimize what is sent over the network.
|
|
||||||
movie = minimize(movie);
|
|
||||||
|
|
||||||
return movie;
|
|
||||||
};
|
|
||||||
|
|
||||||
function minimize(movie: MovieDetails): MovieDetails {
|
|
||||||
const { id, title, release_date, director, producer } = movie;
|
|
||||||
const minimizedMovie = { id, title, release_date, director, producer };
|
|
||||||
return minimizedMovie;
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { useData } from "vike-react/useData";
|
|
||||||
import type { Data } from "./+data.js";
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
const movies = useData<Data>();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h1>Star Wars Movies</h1>
|
|
||||||
<ol>
|
|
||||||
{movies.map(({ id, title, release_date }) => (
|
|
||||||
<li key={id}>
|
|
||||||
<a href={`/star-wars/${id}`}>{title}</a> ({release_date})
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ol>
|
|
||||||
<p>
|
|
||||||
Source: <a href="https://brillout.github.io/star-wars">brillout.github.io/star-wars</a>.
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
// https://vike.dev/data
|
|
||||||
|
|
||||||
import type { Movie, MovieDetails } from "../types.js";
|
|
||||||
import { useConfig } from "vike-react/useConfig";
|
|
||||||
|
|
||||||
export type Data = Awaited<ReturnType<typeof data>>;
|
|
||||||
|
|
||||||
export const data = async () => {
|
|
||||||
// https://vike.dev/useConfig
|
|
||||||
const config = useConfig();
|
|
||||||
|
|
||||||
const response = await fetch("https://brillout.github.io/star-wars/api/films.json");
|
|
||||||
const moviesData = (await response.json()) as MovieDetails[];
|
|
||||||
|
|
||||||
config({
|
|
||||||
// Set <title>
|
|
||||||
title: `${moviesData.length} Star Wars Movies`,
|
|
||||||
});
|
|
||||||
|
|
||||||
// We remove data we don't need because the data is passed to the client; we should
|
|
||||||
// minimize what is sent over the network.
|
|
||||||
const movies = minimize(moviesData);
|
|
||||||
|
|
||||||
return movies;
|
|
||||||
};
|
|
||||||
|
|
||||||
function minimize(movies: MovieDetails[]): Movie[] {
|
|
||||||
return movies.map((movie) => {
|
|
||||||
const { title, release_date, id } = movie;
|
|
||||||
return { title, release_date, id };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
export type Movie = {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
release_date: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MovieDetails = Movie & {
|
|
||||||
director: string;
|
|
||||||
producer: string;
|
|
||||||
};
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import type { Data } from "./+data";
|
|
||||||
import React from "react";
|
|
||||||
import { useData } from "vike-react/useData";
|
|
||||||
import { TodoList } from "./TodoList.js";
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
const data = useData<Data>();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h1>To-do List</h1>
|
|
||||||
<TodoList initialTodoItems={data.todo} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
export const config = {
|
|
||||||
prerender: false,
|
|
||||||
};
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
// https://vike.dev/data
|
|
||||||
import { todos } from "../../database/todoItems";
|
|
||||||
import type { PageContextServer } from "vike/types";
|
|
||||||
|
|
||||||
export type Data = {
|
|
||||||
todo: { text: string }[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async function data(_pageContext: PageContextServer): Promise<Data> {
|
|
||||||
return { todo: todos };
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
// We use Telefunc (https://telefunc.com) for data mutations. Being able to use Telefunc for fetching initial data is work-in-progress (https://vike.dev/data-fetching#tools).
|
|
||||||
|
|
||||||
import { todos } from "../../database/todoItems";
|
|
||||||
|
|
||||||
export async function onNewTodo({ text }: { text: string }) {
|
|
||||||
todos.push({ text });
|
|
||||||
}
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
import { onNewTodo } from "./TodoList.telefunc";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
|
|
||||||
export function TodoList({ initialTodoItems }: { initialTodoItems: { text: string }[] }) {
|
|
||||||
const [todoItems, setTodoItems] = useState(initialTodoItems);
|
|
||||||
const [newTodo, setNewTodo] = useState("");
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ul>
|
|
||||||
{todoItems.map((todoItem, index) => (
|
|
||||||
// biome-ignore lint:
|
|
||||||
<li key={index}>{todoItem.text}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<div>
|
|
||||||
<form
|
|
||||||
onSubmit={async (ev) => {
|
|
||||||
ev.preventDefault();
|
|
||||||
|
|
||||||
// Optimistic UI update
|
|
||||||
setTodoItems((prev) => [...prev, { text: newTodo }]);
|
|
||||||
try {
|
|
||||||
await onNewTodo({ text: newTodo });
|
|
||||||
setNewTodo("");
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
// rollback
|
|
||||||
setTodoItems((prev) => prev.slice(0, -1));
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
onChange={(ev) => setNewTodo(ev.target.value)}
|
|
||||||
value={newTodo}
|
|
||||||
className={
|
|
||||||
"bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-purple-500 focus:border-purple-500 w-full sm:w-auto p-2 mr-1 mb-1"
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className={
|
|
||||||
"text-white bg-purple-700 hover:bg-purple-800 focus:ring-2 focus:outline-hidden focus:ring-purple-300 font-medium rounded-lg text-sm w-full sm:w-auto p-2"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Add to-do
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
98
app/pnpm-lock.yaml
generated
98
app/pnpm-lock.yaml
generated
@ -26,6 +26,9 @@ importers:
|
|||||||
'@headlessui/react':
|
'@headlessui/react':
|
||||||
specifier: ^2.2.0
|
specifier: ^2.2.0
|
||||||
version: 2.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
version: 2.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
|
'@heroicons/react':
|
||||||
|
specifier: ^2.2.0
|
||||||
|
version: 2.2.0(react@19.0.0)
|
||||||
'@markdoc/markdoc':
|
'@markdoc/markdoc':
|
||||||
specifier: ^0.5.1
|
specifier: ^0.5.1
|
||||||
version: 0.5.1(@types/react@19.0.10)(react@19.0.0)
|
version: 0.5.1(@types/react@19.0.10)(react@19.0.0)
|
||||||
@ -74,6 +77,9 @@ importers:
|
|||||||
react-highlight-words:
|
react-highlight-words:
|
||||||
specifier: ^0.21.0
|
specifier: ^0.21.0
|
||||||
version: 0.21.0(react@19.0.0)
|
version: 0.21.0(react@19.0.0)
|
||||||
|
reading-time-estimator:
|
||||||
|
specifier: ^1.12.0
|
||||||
|
version: 1.12.0
|
||||||
simple-functional-loader:
|
simple-functional-loader:
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
@ -719,6 +725,11 @@ packages:
|
|||||||
react: ^18 || ^19 || ^19.0.0-rc
|
react: ^18 || ^19 || ^19.0.0-rc
|
||||||
react-dom: ^18 || ^19 || ^19.0.0-rc
|
react-dom: ^18 || ^19 || ^19.0.0-rc
|
||||||
|
|
||||||
|
'@heroicons/react@2.2.0':
|
||||||
|
resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>= 16 || ^19.0.0-rc'
|
||||||
|
|
||||||
'@humanfs/core@0.19.1':
|
'@humanfs/core@0.19.1':
|
||||||
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
||||||
engines: {node: '>=18.18.0'}
|
engines: {node: '>=18.18.0'}
|
||||||
@ -1401,6 +1412,10 @@ packages:
|
|||||||
deep-is@0.1.4:
|
deep-is@0.1.4:
|
||||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||||
|
|
||||||
|
deepmerge@4.3.1:
|
||||||
|
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
define-data-property@1.1.4:
|
define-data-property@1.1.4:
|
||||||
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
|
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -1425,6 +1440,19 @@ packages:
|
|||||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
dom-serializer@2.0.0:
|
||||||
|
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
|
||||||
|
|
||||||
|
domelementtype@2.3.0:
|
||||||
|
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
||||||
|
|
||||||
|
domhandler@5.0.3:
|
||||||
|
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||||
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
|
domutils@3.2.2:
|
||||||
|
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
|
||||||
|
|
||||||
dunder-proto@1.0.1:
|
dunder-proto@1.0.1:
|
||||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -1449,6 +1477,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
|
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
|
entities@4.5.0:
|
||||||
|
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||||
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
es-abstract@1.23.9:
|
es-abstract@1.23.9:
|
||||||
resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==}
|
resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -1772,6 +1804,9 @@ packages:
|
|||||||
highlight-words-core@1.2.3:
|
highlight-words-core@1.2.3:
|
||||||
resolution: {integrity: sha512-m1O9HW3/GNHxzSIXWw1wCNXXsgLlxrP0OI6+ycGUhiUHkikqW3OrwVHz+lxeNBe5yqLESdIcj8PowHQ2zLvUvQ==}
|
resolution: {integrity: sha512-m1O9HW3/GNHxzSIXWw1wCNXXsgLlxrP0OI6+ycGUhiUHkikqW3OrwVHz+lxeNBe5yqLESdIcj8PowHQ2zLvUvQ==}
|
||||||
|
|
||||||
|
htmlparser2@8.0.2:
|
||||||
|
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
||||||
|
|
||||||
http-errors@2.0.0:
|
http-errors@2.0.0:
|
||||||
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
@ -1867,6 +1902,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
|
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
|
||||||
engines: {node: '>=0.12.0'}
|
engines: {node: '>=0.12.0'}
|
||||||
|
|
||||||
|
is-plain-object@5.0.0:
|
||||||
|
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
is-regex@1.2.1:
|
is-regex@1.2.1:
|
||||||
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
|
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -2180,6 +2219,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
parse-srcset@1.0.2:
|
||||||
|
resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
|
||||||
|
|
||||||
path-browserify@1.0.1:
|
path-browserify@1.0.1:
|
||||||
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
||||||
|
|
||||||
@ -2310,6 +2352,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==}
|
resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
reading-time-estimator@1.12.0:
|
||||||
|
resolution: {integrity: sha512-A17wehSIG6bxen84mf5m+MP4bDDZytcfMOfJWDp1DT8StGRgljtD58zC6E+fSnQZvU5mfsjiJZ7BLhr9kHYoQQ==}
|
||||||
|
|
||||||
real-require@0.2.0:
|
real-require@0.2.0:
|
||||||
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
|
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
|
||||||
engines: {node: '>= 12.13.0'}
|
engines: {node: '>= 12.13.0'}
|
||||||
@ -2385,6 +2430,9 @@ packages:
|
|||||||
safer-buffer@2.1.2:
|
safer-buffer@2.1.2:
|
||||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||||
|
|
||||||
|
sanitize-html@2.15.0:
|
||||||
|
resolution: {integrity: sha512-wIjst57vJGpLyBP8ioUbg6ThwJie5SuSIjHxJg53v5Fg+kUK+AXlb7bK3RNXpp315MvwM+0OBGCV6h5pPHsVhA==}
|
||||||
|
|
||||||
scheduler@0.25.0:
|
scheduler@0.25.0:
|
||||||
resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==}
|
resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==}
|
||||||
|
|
||||||
@ -3298,6 +3346,10 @@ snapshots:
|
|||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
react-dom: 19.0.0(react@19.0.0)
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
|
|
||||||
|
'@heroicons/react@2.2.0(react@19.0.0)':
|
||||||
|
dependencies:
|
||||||
|
react: 19.0.0
|
||||||
|
|
||||||
'@humanfs/core@0.19.1': {}
|
'@humanfs/core@0.19.1': {}
|
||||||
|
|
||||||
'@humanfs/node@0.16.6':
|
'@humanfs/node@0.16.6':
|
||||||
@ -4007,6 +4059,8 @@ snapshots:
|
|||||||
|
|
||||||
deep-is@0.1.4: {}
|
deep-is@0.1.4: {}
|
||||||
|
|
||||||
|
deepmerge@4.3.1: {}
|
||||||
|
|
||||||
define-data-property@1.1.4:
|
define-data-property@1.1.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-define-property: 1.0.1
|
es-define-property: 1.0.1
|
||||||
@ -4029,6 +4083,24 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
|
|
||||||
|
dom-serializer@2.0.0:
|
||||||
|
dependencies:
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
domhandler: 5.0.3
|
||||||
|
entities: 4.5.0
|
||||||
|
|
||||||
|
domelementtype@2.3.0: {}
|
||||||
|
|
||||||
|
domhandler@5.0.3:
|
||||||
|
dependencies:
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
|
||||||
|
domutils@3.2.2:
|
||||||
|
dependencies:
|
||||||
|
dom-serializer: 2.0.0
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
domhandler: 5.0.3
|
||||||
|
|
||||||
dunder-proto@1.0.1:
|
dunder-proto@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind-apply-helpers: 1.0.2
|
call-bind-apply-helpers: 1.0.2
|
||||||
@ -4050,6 +4122,8 @@ snapshots:
|
|||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
tapable: 2.2.1
|
tapable: 2.2.1
|
||||||
|
|
||||||
|
entities@4.5.0: {}
|
||||||
|
|
||||||
es-abstract@1.23.9:
|
es-abstract@1.23.9:
|
||||||
dependencies:
|
dependencies:
|
||||||
array-buffer-byte-length: 1.0.2
|
array-buffer-byte-length: 1.0.2
|
||||||
@ -4535,6 +4609,13 @@ snapshots:
|
|||||||
|
|
||||||
highlight-words-core@1.2.3: {}
|
highlight-words-core@1.2.3: {}
|
||||||
|
|
||||||
|
htmlparser2@8.0.2:
|
||||||
|
dependencies:
|
||||||
|
domelementtype: 2.3.0
|
||||||
|
domhandler: 5.0.3
|
||||||
|
domutils: 3.2.2
|
||||||
|
entities: 4.5.0
|
||||||
|
|
||||||
http-errors@2.0.0:
|
http-errors@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
depd: 2.0.0
|
depd: 2.0.0
|
||||||
@ -4634,6 +4715,8 @@ snapshots:
|
|||||||
|
|
||||||
is-number@7.0.0: {}
|
is-number@7.0.0: {}
|
||||||
|
|
||||||
|
is-plain-object@5.0.0: {}
|
||||||
|
|
||||||
is-regex@1.2.1:
|
is-regex@1.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bound: 1.0.4
|
call-bound: 1.0.4
|
||||||
@ -4918,6 +5001,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
callsites: 3.1.0
|
callsites: 3.1.0
|
||||||
|
|
||||||
|
parse-srcset@1.0.2: {}
|
||||||
|
|
||||||
path-browserify@1.0.1: {}
|
path-browserify@1.0.1: {}
|
||||||
|
|
||||||
path-exists@4.0.0: {}
|
path-exists@4.0.0: {}
|
||||||
@ -5043,6 +5128,10 @@ snapshots:
|
|||||||
|
|
||||||
react@19.0.0: {}
|
react@19.0.0: {}
|
||||||
|
|
||||||
|
reading-time-estimator@1.12.0:
|
||||||
|
dependencies:
|
||||||
|
sanitize-html: 2.15.0
|
||||||
|
|
||||||
real-require@0.2.0: {}
|
real-require@0.2.0: {}
|
||||||
|
|
||||||
reflect.getprototypeof@1.0.10:
|
reflect.getprototypeof@1.0.10:
|
||||||
@ -5143,6 +5232,15 @@ snapshots:
|
|||||||
|
|
||||||
safer-buffer@2.1.2: {}
|
safer-buffer@2.1.2: {}
|
||||||
|
|
||||||
|
sanitize-html@2.15.0:
|
||||||
|
dependencies:
|
||||||
|
deepmerge: 4.3.1
|
||||||
|
escape-string-regexp: 4.0.0
|
||||||
|
htmlparser2: 8.0.2
|
||||||
|
is-plain-object: 5.0.0
|
||||||
|
parse-srcset: 1.0.2
|
||||||
|
postcss: 8.5.3
|
||||||
|
|
||||||
scheduler@0.25.0: {}
|
scheduler@0.25.0: {}
|
||||||
|
|
||||||
search-insights@2.17.3: {}
|
search-insights@2.17.3: {}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user