mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-24 06:27:02 +02:00
refactor(theme): dates should be formatted on the client-side instead of in nodejs code (#9868)
Co-authored-by: OzakIOne <OzakIOne@users.noreply.github.com> Co-authored-by: sebastien <lorber.sebastien@gmail.com>
This commit is contained in:
parent
6bf21d215c
commit
0279c329ad
15 changed files with 83 additions and 162 deletions
|
@ -41,6 +41,7 @@ const markdown: MarkdownConfig = {
|
|||
}
|
||||
return result;
|
||||
},
|
||||
remarkRehypeOptions: undefined,
|
||||
};
|
||||
|
||||
function findByTitle(
|
||||
|
@ -175,7 +176,6 @@ describe('blog plugin', () => {
|
|||
description: `date inside front matter`,
|
||||
authors: [],
|
||||
date: new Date('2019-01-01'),
|
||||
formattedDate: 'January 1, 2019',
|
||||
frontMatter: {
|
||||
date: new Date('2019-01-01'),
|
||||
tags: ['date'],
|
||||
|
@ -220,7 +220,6 @@ describe('blog plugin', () => {
|
|||
},
|
||||
],
|
||||
date: new Date('2018-12-14'),
|
||||
formattedDate: 'December 14, 2018',
|
||||
frontMatter: {
|
||||
authors: [
|
||||
{
|
||||
|
@ -256,7 +255,6 @@ describe('blog plugin', () => {
|
|||
title: 'Simple Slug',
|
||||
},
|
||||
date: new Date('2020-08-16'),
|
||||
formattedDate: 'August 16, 2020',
|
||||
frontMatter: {
|
||||
date: '2020/08/16',
|
||||
slug: '/hey/my super path/héllô',
|
||||
|
@ -302,7 +300,6 @@ describe('blog plugin', () => {
|
|||
title: 'draft',
|
||||
},
|
||||
date: new Date('2020-08-15'),
|
||||
formattedDate: 'August 15, 2020',
|
||||
frontMatter: {
|
||||
author: 'Sébastien Lorber',
|
||||
author_title: 'Docusaurus maintainer',
|
||||
|
@ -328,7 +325,6 @@ describe('blog plugin', () => {
|
|||
description: '',
|
||||
authors: [],
|
||||
date: new Date('2019-01-02'),
|
||||
formattedDate: 'January 2, 2019',
|
||||
frontMatter: {
|
||||
date: new Date('2019-01-02'),
|
||||
},
|
||||
|
@ -343,39 +339,6 @@ describe('blog plugin', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('builds simple website blog with localized dates', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'website');
|
||||
const blogPostsFrench = await getBlogPosts(siteDir, {}, getI18n('fr'));
|
||||
expect(blogPostsFrench).toHaveLength(10);
|
||||
expect(blogPostsFrench[0]!.metadata.formattedDate).toMatchInlineSnapshot(
|
||||
`"23 juillet 2023"`,
|
||||
);
|
||||
expect(blogPostsFrench[1]!.metadata.formattedDate).toMatchInlineSnapshot(
|
||||
`"6 mars 2021"`,
|
||||
);
|
||||
expect(blogPostsFrench[2]!.metadata.formattedDate).toMatchInlineSnapshot(
|
||||
`"5 mars 2021"`,
|
||||
);
|
||||
expect(blogPostsFrench[3]!.metadata.formattedDate).toMatchInlineSnapshot(
|
||||
`"16 août 2020"`,
|
||||
);
|
||||
expect(blogPostsFrench[4]!.metadata.formattedDate).toMatchInlineSnapshot(
|
||||
`"15 août 2020"`,
|
||||
);
|
||||
expect(blogPostsFrench[5]!.metadata.formattedDate).toMatchInlineSnapshot(
|
||||
`"27 février 2020"`,
|
||||
);
|
||||
expect(blogPostsFrench[6]!.metadata.formattedDate).toMatchInlineSnapshot(
|
||||
`"27 février 2020"`,
|
||||
);
|
||||
expect(blogPostsFrench[7]!.metadata.formattedDate).toMatchInlineSnapshot(
|
||||
`"2 janvier 2019"`,
|
||||
);
|
||||
expect(blogPostsFrench[8]!.metadata.formattedDate).toMatchInlineSnapshot(
|
||||
`"1 janvier 2019"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('handles edit URL with editLocalizedBlogs: true', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'website');
|
||||
const blogPosts = await getBlogPosts(siteDir, {editLocalizedFiles: true});
|
||||
|
@ -476,11 +439,6 @@ describe('blog plugin', () => {
|
|||
// We know the file exists and we know we have git
|
||||
const result = getFileCommitDate(noDateSourceFile, {age: 'oldest'});
|
||||
const noDateSourceTime = result.date;
|
||||
const formattedDate = Intl.DateTimeFormat('en', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
}).format(noDateSourceTime);
|
||||
|
||||
expect({
|
||||
...getByTitle(blogPosts, 'no date').metadata,
|
||||
|
@ -494,7 +452,6 @@ describe('blog plugin', () => {
|
|||
description: `no date`,
|
||||
authors: [],
|
||||
date: noDateSourceTime,
|
||||
formattedDate,
|
||||
frontMatter: {},
|
||||
tags: [],
|
||||
prevItem: undefined,
|
||||
|
|
|
@ -164,25 +164,6 @@ export function parseBlogFileName(
|
|||
return {date: undefined, text, slug};
|
||||
}
|
||||
|
||||
function formatBlogPostDate(
|
||||
locale: string,
|
||||
date: Date,
|
||||
calendar: string,
|
||||
): string {
|
||||
try {
|
||||
return new Intl.DateTimeFormat(locale, {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
timeZone: 'UTC',
|
||||
calendar,
|
||||
}).format(date);
|
||||
} catch (err) {
|
||||
logger.error`Can't format blog post date "${String(date)}"`;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function parseBlogPostMarkdownFile({
|
||||
filePath,
|
||||
parseFrontMatter,
|
||||
|
@ -289,11 +270,6 @@ async function processBlogSourceFile(
|
|||
}
|
||||
|
||||
const date = await getDate();
|
||||
const formattedDate = formatBlogPostDate(
|
||||
i18n.currentLocale,
|
||||
date,
|
||||
i18n.localeConfigs[i18n.currentLocale]!.calendar,
|
||||
);
|
||||
|
||||
const title = frontMatter.title ?? contentTitle ?? parsedBlogFileName.text;
|
||||
const description = frontMatter.description ?? excerpt ?? '';
|
||||
|
@ -348,7 +324,6 @@ async function processBlogSourceFile(
|
|||
title,
|
||||
description,
|
||||
date,
|
||||
formattedDate,
|
||||
tags: normalizeFrontMatterTags(tagsBasePath, frontMatter.tags),
|
||||
readingTime: showReadingTime
|
||||
? options.readingTime({
|
||||
|
|
|
@ -192,11 +192,6 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
|
|||
* into a string.
|
||||
*/
|
||||
readonly date: Date;
|
||||
/**
|
||||
* Publish date formatted according to the locale, so that the client can
|
||||
* render the date regardless of the existence of `Intl.DateTimeFormat`.
|
||||
*/
|
||||
readonly formattedDate: string;
|
||||
/** Full link including base URL. */
|
||||
readonly permalink: string;
|
||||
/**
|
||||
|
|
|
@ -52,7 +52,6 @@ exports[`simple website content 1`] = `
|
|||
"description": "Images",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"id": "baz",
|
||||
"pagination_label": "baz pagination_label",
|
||||
|
@ -105,7 +104,6 @@ exports[`simple website content 2`] = `
|
|||
"description": "Hi, Endilie here :)",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"id": "hello",
|
||||
"sidebar_label": "Hello sidebar_label",
|
||||
|
@ -151,7 +149,6 @@ exports[`simple website content 3`] = `
|
|||
"description": "This is custom description",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"description": "This is custom description",
|
||||
"id": "bar",
|
||||
|
@ -1971,7 +1968,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Getting started text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "getting-started",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -1999,7 +1995,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Installation text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "installation",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -2030,7 +2025,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Guide 1 text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"id": "guide1",
|
||||
"sidebar_position": 1,
|
||||
|
@ -2064,7 +2058,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Guide 2 text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"id": "guide2",
|
||||
},
|
||||
|
@ -2097,7 +2090,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Guide 2.5 text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"id": "guide2.5",
|
||||
"sidebar_position": 2.5,
|
||||
|
@ -2131,7 +2123,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Guide 3 text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"id": "guide3",
|
||||
"sidebar_position": 3,
|
||||
|
@ -2165,7 +2156,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Guide 4 text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"id": "guide4",
|
||||
},
|
||||
|
@ -2198,7 +2188,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Guide 5 text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"id": "guide5",
|
||||
},
|
||||
|
@ -2231,7 +2220,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "API Overview text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "API/api-overview",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -2262,7 +2250,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Client API text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "API/Core APIs/Client API",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -2293,7 +2280,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Server API text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "API/Core APIs/Server API",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -2324,7 +2310,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Plugin API text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "API/Extension APIs/Plugin API",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -2355,7 +2340,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "Theme API text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "API/Extension APIs/Theme API",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -2386,7 +2370,6 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha
|
|||
"description": "API End text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "API/api-end",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -2566,7 +2549,6 @@ exports[`site with partial autogenerated sidebars docs in partially generated si
|
|||
"description": "API End text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "API/api-end",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -2594,7 +2576,6 @@ exports[`site with partial autogenerated sidebars docs in partially generated si
|
|||
"description": "API Overview text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "API/api-overview",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -2625,7 +2606,6 @@ exports[`site with partial autogenerated sidebars docs in partially generated si
|
|||
"description": "Plugin API text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "API/Extension APIs/Plugin API",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -2656,7 +2636,6 @@ exports[`site with partial autogenerated sidebars docs in partially generated si
|
|||
"description": "Theme API text",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "API/Extension APIs/Theme API",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -2716,7 +2695,6 @@ exports[`versioned website (community) content 1`] = `
|
|||
"description": "Team current version (translated)",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"title": "Team title translated",
|
||||
},
|
||||
|
@ -2743,7 +2721,6 @@ exports[`versioned website (community) content 2`] = `
|
|||
"description": "Team 1.0.0",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "team",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -3023,7 +3000,6 @@ exports[`versioned website content 1`] = `
|
|||
"description": "This is next version of bar.",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"slug": "barSlug",
|
||||
"tags": [
|
||||
|
@ -3074,7 +3050,6 @@ exports[`versioned website content 2`] = `
|
|||
"description": "Bar 1.0.1 !",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "foo/bar",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
@ -3102,7 +3077,6 @@ exports[`versioned website content 3`] = `
|
|||
"description": "Hello next !",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"slug": "/",
|
||||
},
|
||||
|
@ -3132,7 +3106,6 @@ exports[`versioned website content 4`] = `
|
|||
"description": "Hello 1.0.1 !",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {
|
||||
"slug": "/",
|
||||
},
|
||||
|
@ -3162,7 +3135,6 @@ exports[`versioned website content 5`] = `
|
|||
"description": "Baz 1.0.0 ! This will be deleted in next subsequent versions.",
|
||||
"draft": false,
|
||||
"editUrl": undefined,
|
||||
"formattedLastUpdatedAt": undefined,
|
||||
"frontMatter": {},
|
||||
"id": "foo/baz",
|
||||
"lastUpdatedAt": undefined,
|
||||
|
|
|
@ -475,7 +475,6 @@ describe('simple site', () => {
|
|||
unrelated_front_matter: "won't be part of metadata",
|
||||
},
|
||||
lastUpdatedAt: 1539502055,
|
||||
formattedLastUpdatedAt: 'Oct 14, 2018',
|
||||
lastUpdatedBy: 'Author',
|
||||
tags: [],
|
||||
unlisted: false,
|
||||
|
@ -573,7 +572,6 @@ describe('simple site', () => {
|
|||
title: 'Custom Last Update',
|
||||
},
|
||||
lastUpdatedAt: new Date('1/1/2000').getTime() / 1000,
|
||||
formattedLastUpdatedAt: 'Jan 1, 2000',
|
||||
lastUpdatedBy: 'Custom Author (processed by parseFrontMatter)',
|
||||
sidebarPosition: undefined,
|
||||
tags: [],
|
||||
|
@ -612,7 +610,6 @@ describe('simple site', () => {
|
|||
title: 'Last Update Author Only',
|
||||
},
|
||||
lastUpdatedAt: 1539502055,
|
||||
formattedLastUpdatedAt: 'Oct 14, 2018',
|
||||
lastUpdatedBy: 'Custom Author (processed by parseFrontMatter)',
|
||||
sidebarPosition: undefined,
|
||||
tags: [],
|
||||
|
@ -651,7 +648,6 @@ describe('simple site', () => {
|
|||
title: 'Last Update Date Only',
|
||||
},
|
||||
lastUpdatedAt: new Date('1/1/2000').getTime() / 1000,
|
||||
formattedLastUpdatedAt: 'Jan 1, 2000',
|
||||
lastUpdatedBy: 'Author',
|
||||
sidebarPosition: undefined,
|
||||
tags: [],
|
||||
|
@ -691,7 +687,6 @@ describe('simple site', () => {
|
|||
title: 'Custom Last Update',
|
||||
},
|
||||
lastUpdatedAt: undefined,
|
||||
formattedLastUpdatedAt: undefined,
|
||||
lastUpdatedBy: undefined,
|
||||
sidebarPosition: undefined,
|
||||
tags: [],
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import _ from 'lodash';
|
||||
import logger from '@docusaurus/logger';
|
||||
import {
|
||||
aliasedSitePath,
|
||||
getEditUrl,
|
||||
|
@ -142,7 +141,6 @@ async function doProcessDocMetadata({
|
|||
const {source, content, contentPath, filePath} = docFile;
|
||||
const {
|
||||
siteDir,
|
||||
i18n,
|
||||
siteConfig: {
|
||||
markdown: {parseFrontMatter},
|
||||
},
|
||||
|
@ -257,21 +255,6 @@ async function doProcessDocMetadata({
|
|||
const draft = isDraft({env, frontMatter});
|
||||
const unlisted = isUnlisted({env, frontMatter});
|
||||
|
||||
const formatDate = (locale: string, date: Date, calendar: string): string => {
|
||||
try {
|
||||
return new Intl.DateTimeFormat(locale, {
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
timeZone: 'UTC',
|
||||
calendar,
|
||||
}).format(date);
|
||||
} catch (err) {
|
||||
logger.error`Can't format docs lastUpdatedAt date "${String(date)}"`;
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
// Assign all of object properties during instantiation (if possible) for
|
||||
// NodeJS optimization.
|
||||
// Adding properties to object after instantiation will cause hidden
|
||||
|
@ -291,13 +274,6 @@ async function doProcessDocMetadata({
|
|||
version: versionMetadata.versionName,
|
||||
lastUpdatedBy: lastUpdate.lastUpdatedBy,
|
||||
lastUpdatedAt: lastUpdate.lastUpdatedAt,
|
||||
formattedLastUpdatedAt: lastUpdate.lastUpdatedAt
|
||||
? formatDate(
|
||||
i18n.currentLocale,
|
||||
new Date(lastUpdate.lastUpdatedAt * 1000),
|
||||
i18n.localeConfigs[i18n.currentLocale]!.calendar,
|
||||
)
|
||||
: undefined,
|
||||
sidebarPosition,
|
||||
frontMatter,
|
||||
};
|
||||
|
|
|
@ -407,8 +407,6 @@ declare module '@docusaurus/plugin-content-docs' {
|
|||
export type LastUpdateData = {
|
||||
/** A timestamp in **seconds**, directly acquired from `git log`. */
|
||||
lastUpdatedAt?: number;
|
||||
/** `lastUpdatedAt` formatted as a date according to the current locale. */
|
||||
formattedLastUpdatedAt?: string;
|
||||
/** The author's name directly acquired from `git log`. */
|
||||
lastUpdatedBy?: string;
|
||||
};
|
||||
|
|
|
@ -824,7 +824,6 @@ declare module '@theme/SearchMetadata' {
|
|||
declare module '@theme/LastUpdated' {
|
||||
export interface Props {
|
||||
readonly lastUpdatedAt?: number;
|
||||
readonly formattedLastUpdatedAt?: string;
|
||||
readonly lastUpdatedBy?: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import React from 'react';
|
|||
import Link from '@docusaurus/Link';
|
||||
import {translate} from '@docusaurus/Translate';
|
||||
import {PageMetadata} from '@docusaurus/theme-common';
|
||||
import {useDateTimeFormat} from '@docusaurus/theme-common/internal';
|
||||
import Layout from '@theme/Layout';
|
||||
import type {ArchiveBlogPost, Props} from '@theme/BlogArchivePage';
|
||||
import Heading from '@theme/Heading';
|
||||
|
@ -19,6 +20,15 @@ type YearProp = {
|
|||
};
|
||||
|
||||
function Year({year, posts}: YearProp) {
|
||||
const dateTimeFormat = useDateTimeFormat({
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
timeZone: 'UTC',
|
||||
});
|
||||
|
||||
const formatDate = (lastUpdated: string) =>
|
||||
dateTimeFormat.format(new Date(lastUpdated));
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading as="h3" id={year}>
|
||||
|
@ -28,7 +38,7 @@ function Year({year, posts}: YearProp) {
|
|||
{posts.map((post) => (
|
||||
<li key={post.metadata.date}>
|
||||
<Link to={post.metadata.permalink}>
|
||||
{post.metadata.formattedDate} - {post.metadata.title}
|
||||
{formatDate(post.metadata.date)} - {post.metadata.title}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
|
|
|
@ -9,7 +9,10 @@ import React from 'react';
|
|||
import clsx from 'clsx';
|
||||
import {translate} from '@docusaurus/Translate';
|
||||
import {usePluralForm} from '@docusaurus/theme-common';
|
||||
import {useBlogPost} from '@docusaurus/theme-common/internal';
|
||||
import {
|
||||
useBlogPost,
|
||||
useDateTimeFormat,
|
||||
} from '@docusaurus/theme-common/internal';
|
||||
import type {Props} from '@theme/BlogPostItem/Header/Info';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
@ -39,7 +42,13 @@ function ReadingTime({readingTime}: {readingTime: number}) {
|
|||
return <>{readingTimePlural(readingTime)}</>;
|
||||
}
|
||||
|
||||
function Date({date, formattedDate}: {date: string; formattedDate: string}) {
|
||||
function DateTime({
|
||||
date,
|
||||
formattedDate,
|
||||
}: {
|
||||
date: string;
|
||||
formattedDate: string;
|
||||
}) {
|
||||
return <time dateTime={date}>{formattedDate}</time>;
|
||||
}
|
||||
|
||||
|
@ -51,11 +60,21 @@ export default function BlogPostItemHeaderInfo({
|
|||
className,
|
||||
}: Props): JSX.Element {
|
||||
const {metadata} = useBlogPost();
|
||||
const {date, formattedDate, readingTime} = metadata;
|
||||
const {date, readingTime} = metadata;
|
||||
|
||||
const dateTimeFormat = useDateTimeFormat({
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
timeZone: 'UTC',
|
||||
});
|
||||
|
||||
const formatDate = (blogDate: string) =>
|
||||
dateTimeFormat.format(new Date(blogDate));
|
||||
|
||||
return (
|
||||
<div className={clsx(styles.container, 'margin-vert--md', className)}>
|
||||
<Date date={date} formattedDate={formattedDate} />
|
||||
<DateTime date={date} formattedDate={formatDate(date)} />
|
||||
{typeof readingTime !== 'undefined' && (
|
||||
<>
|
||||
<Spacer />
|
||||
|
|
|
@ -33,13 +33,12 @@ function TagsRow(props: TagsListInlineProps) {
|
|||
|
||||
type EditMetaRowProps = Pick<
|
||||
DocContextValue['metadata'],
|
||||
'editUrl' | 'lastUpdatedAt' | 'lastUpdatedBy' | 'formattedLastUpdatedAt'
|
||||
'editUrl' | 'lastUpdatedAt' | 'lastUpdatedBy'
|
||||
>;
|
||||
function EditMetaRow({
|
||||
editUrl,
|
||||
lastUpdatedAt,
|
||||
lastUpdatedBy,
|
||||
formattedLastUpdatedAt,
|
||||
}: EditMetaRowProps) {
|
||||
return (
|
||||
<div className={clsx(ThemeClassNames.docs.docFooterEditMetaRow, 'row')}>
|
||||
|
@ -49,7 +48,6 @@ function EditMetaRow({
|
|||
{(lastUpdatedAt || lastUpdatedBy) && (
|
||||
<LastUpdated
|
||||
lastUpdatedAt={lastUpdatedAt}
|
||||
formattedLastUpdatedAt={formattedLastUpdatedAt}
|
||||
lastUpdatedBy={lastUpdatedBy}
|
||||
/>
|
||||
)}
|
||||
|
@ -60,8 +58,7 @@ function EditMetaRow({
|
|||
|
||||
export default function DocItemFooter(): JSX.Element | null {
|
||||
const {metadata} = useDoc();
|
||||
const {editUrl, lastUpdatedAt, formattedLastUpdatedAt, lastUpdatedBy, tags} =
|
||||
metadata;
|
||||
const {editUrl, lastUpdatedAt, lastUpdatedBy, tags} = metadata;
|
||||
|
||||
const canDisplayTagsRow = tags.length > 0;
|
||||
const canDisplayEditMetaRow = !!(editUrl || lastUpdatedAt || lastUpdatedBy);
|
||||
|
@ -81,7 +78,6 @@ export default function DocItemFooter(): JSX.Element | null {
|
|||
editUrl={editUrl}
|
||||
lastUpdatedAt={lastUpdatedAt}
|
||||
lastUpdatedBy={lastUpdatedBy}
|
||||
formattedLastUpdatedAt={formattedLastUpdatedAt}
|
||||
/>
|
||||
)}
|
||||
</footer>
|
||||
|
|
|
@ -8,15 +8,25 @@
|
|||
import React from 'react';
|
||||
import Translate from '@docusaurus/Translate';
|
||||
import {ThemeClassNames} from '@docusaurus/theme-common';
|
||||
import {useDateTimeFormat} from '@docusaurus/theme-common/internal';
|
||||
import type {Props} from '@theme/LastUpdated';
|
||||
|
||||
function LastUpdatedAtDate({
|
||||
lastUpdatedAt,
|
||||
formattedLastUpdatedAt,
|
||||
}: {
|
||||
lastUpdatedAt: number;
|
||||
formattedLastUpdatedAt: string;
|
||||
}): JSX.Element {
|
||||
const atDate = new Date(lastUpdatedAt * 1000);
|
||||
|
||||
const dateTimeFormat = useDateTimeFormat({
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
timeZone: 'UTC',
|
||||
});
|
||||
|
||||
const formattedLastUpdatedAt = dateTimeFormat.format(atDate);
|
||||
|
||||
return (
|
||||
<Translate
|
||||
id="theme.lastUpdated.atDate"
|
||||
|
@ -24,7 +34,7 @@ function LastUpdatedAtDate({
|
|||
values={{
|
||||
date: (
|
||||
<b>
|
||||
<time dateTime={new Date(lastUpdatedAt * 1000).toISOString()}>
|
||||
<time dateTime={atDate.toISOString()}>
|
||||
{formattedLastUpdatedAt}
|
||||
</time>
|
||||
</b>
|
||||
|
@ -54,7 +64,6 @@ function LastUpdatedByUser({
|
|||
|
||||
export default function LastUpdated({
|
||||
lastUpdatedAt,
|
||||
formattedLastUpdatedAt,
|
||||
lastUpdatedBy,
|
||||
}: Props): JSX.Element {
|
||||
return (
|
||||
|
@ -63,12 +72,8 @@ export default function LastUpdated({
|
|||
id="theme.lastUpdated.lastUpdatedAtBy"
|
||||
description="The sentence used to display when a page has been last updated, and by who"
|
||||
values={{
|
||||
atDate:
|
||||
lastUpdatedAt && formattedLastUpdatedAt ? (
|
||||
<LastUpdatedAtDate
|
||||
lastUpdatedAt={lastUpdatedAt}
|
||||
formattedLastUpdatedAt={formattedLastUpdatedAt}
|
||||
/>
|
||||
atDate: lastUpdatedAt ? (
|
||||
<LastUpdatedAtDate lastUpdatedAt={lastUpdatedAt} />
|
||||
) : (
|
||||
''
|
||||
),
|
||||
|
|
|
@ -114,6 +114,7 @@ export {
|
|||
} from './hooks/useTOCHighlight';
|
||||
|
||||
export {useVisibleBlogSidebarItems} from './utils/blogUtils';
|
||||
export {useDateTimeFormat} from './utils/IntlUtils';
|
||||
|
||||
export {useHideableNavbar} from './hooks/useHideableNavbar';
|
||||
export {
|
||||
|
|
27
packages/docusaurus-theme-common/src/utils/IntlUtils.ts
Normal file
27
packages/docusaurus-theme-common/src/utils/IntlUtils.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
|
||||
export function useCalendar(): string {
|
||||
const {
|
||||
i18n: {currentLocale, localeConfigs},
|
||||
} = useDocusaurusContext();
|
||||
return localeConfigs[currentLocale]!.calendar;
|
||||
}
|
||||
|
||||
export function useDateTimeFormat(
|
||||
options: Intl.DateTimeFormatOptions = {},
|
||||
): Intl.DateTimeFormat {
|
||||
const {
|
||||
i18n: {currentLocale},
|
||||
} = useDocusaurusContext();
|
||||
const calendar = useCalendar();
|
||||
return new Intl.DateTimeFormat(currentLocale, {
|
||||
calendar,
|
||||
...options,
|
||||
});
|
||||
}
|
|
@ -8,7 +8,6 @@ algoliasearch
|
|||
Allez
|
||||
Anshul
|
||||
anshul
|
||||
août
|
||||
APFS
|
||||
apfs
|
||||
appinstalled
|
||||
|
@ -105,7 +104,6 @@ Formik
|
|||
FOUC
|
||||
froms
|
||||
funboxteam
|
||||
février
|
||||
gabrielcsapo
|
||||
Gifs
|
||||
Goss
|
||||
|
@ -139,14 +137,12 @@ interactiveness
|
|||
Interpolatable
|
||||
interpolatable
|
||||
Investec
|
||||
janvier
|
||||
javadoc
|
||||
jiti
|
||||
jmarcey
|
||||
jodyheavener
|
||||
joshcena
|
||||
jssdk
|
||||
juillet
|
||||
Kaszubowski
|
||||
Katex
|
||||
katex
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue