astro-accelerator 5.9.21 → 5.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,94 +1,113 @@
1
- /**
2
- * Recommended Tools
3
- * Check accessibility for colour combinations
4
- * https://toolness.github.io/accessible-color-matrix/
5
- *
6
- * @format
7
- */
8
-
9
- :root {
10
- --fore: #333;
11
- --fore-headings: #225;
12
- --aft: #fbfbfc;
1
+ @font-face {
2
+ font-family: "hyper-reg";
3
+ font-weight: normal;
4
+ font-style: normal;
5
+ src: url("AtkinsonHyperlegibleNext-Regular.otf");
6
+ font-display: block;
7
+ }
13
8
 
14
- --fore-link: #2d4295;
15
- --fore-link-alt: #4d71ff;
16
- --aft-link-alt: #f3f5ff;
9
+ @font-face {
10
+ font-family: "hyper-bold";
11
+ font-weight: bold;
12
+ font-style: normal;
13
+ src: url("AtkinsonHyperlegibleNext-Bold.otf");
14
+ font-display: block;
15
+ }
17
16
 
18
- --fore-head: #333;
19
- --aft-head: #e6e8f1;
20
- --icon-head: #2d4295;
17
+ @font-face {
18
+ font-family: "hyper-mono";
19
+ font-weight: bold;
20
+ font-style: normal;
21
+ src: url("AtkinsonHyperlegibleMono-Regular.otf");
22
+ font-display: block;
23
+ }
21
24
 
22
- --fore-breadcrumb: #333;
23
- --aft-breadcrumb: #f3f5ff;
25
+ :root {
26
+ --fore: #233;
27
+ --aft: #DFF;
28
+ --aft-image: #DFF;
24
29
 
25
- --link-head: #2d4295;
26
- --link-alt-head: #2a4dd8;
30
+ --fore-link: #355;
31
+ --fore-link-alt: #699;
32
+ --aft-link-alt: #e6e6eC;
33
+
34
+ --fore-input: var(--fore);
35
+ --aft-input: var(--aft);
27
36
 
28
37
  --fore-block: #333;
29
- --aft-block: #f3f5ff;
30
- --icon-block: #4d71ff;
38
+ --aft-block: #BEE;
39
+ --icon-block: #FF0;
31
40
 
32
- --fore-table-head: #fdfdfe;
33
- --aft-table-head: #2f3141;
41
+ --fore-table-head: #DFF;
42
+ --aft-table-head: #233;
34
43
  --fore-table-row-odd: #333;
35
- --aft-table-row-odd: #fdfdfe;
44
+ --aft-table-row-odd: #DFF;
36
45
  --fore-table-row-even: #333;
37
- --aft-table-row-even: #f3f5ff;
46
+ --aft-table-row-even: #CFF;
47
+
48
+ --heading-font: 'hyper-bold', sans-serif;
49
+ --content-font: 'hyper-reg', Verdana, Geneva, sans-serif;
50
+ --code-font: 'hyper-mono', Consolas, 'Courier New', Courier, monospace;
51
+ --unicode-font: font-family: "Segoe UI Symbol", "Arial Unicode MS", "DejaVu Sans", "Meiryo UI", "MS UI Gothic", "Everson Mono Unicode", Meiryo, "MS Gothic", "MS Mincho", "MS PGothic", "MS PMincho", "Meslo LG L", "Meslo LG L DZ", "Meslo M L", "Meslo M L DZ", "Meslo S L", "Meslo S L DZ", "Symbola", "DejaVu Sans Condensed", "DejaVu Sans Mono", Code2000, "Everson Mono", Quivira, sans-serif;
38
52
 
39
- --heading-font: Georgia, 'Times New Roman', Times, serif;
40
- --content-font: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
41
- --code-font: Consolas, 'Courier New', Courier, monospace;
42
- --unicode-font: 'Segoe UI Symbol', 'Arial Unicode MS', sans-serif;
53
+ --font-size-meta: 0.9rem;
54
+ --font-size-h1: 3rem;
55
+ --font-size-h2: 2.3rem;
56
+ --font-size-h3: 2rem;
57
+ --font-size-h4: 1.7rem;
58
+ --font-size-h5: 1.7rem;
59
+ --font-size-h6: 1.7rem;
43
60
 
61
+ --paragraph-margin: 1.2rem;
44
62
  --block-gap: 2rem;
63
+ --block-gap-l: 3rem;
45
64
  --block-radius: 0.3rem;
65
+ --block-radius-round: 20px;
46
66
 
47
67
  --marker-size: 1.2rem;
48
- --paragraph-margin: 1.2rem;
49
68
 
50
- --box-shadow: 0 12px 24px -12px rgb(0 0 0 / 80%);
69
+ --box-shadow: 0 12px 24px -12px rgb(0 0 0 / 50%);
51
70
  --box-shadow-slight: 0 6px 12px -6px rgb(0 0 0 / 40%);
52
71
 
53
- --content-width: 78vw;
54
- --navigation-width: 260px;
55
- --grid-gap: 1.5rem;
56
- --grid-max-width: 60rem;
57
- --grid-width: 90vw;
72
+ --box-shadow-unselected: rgb(0 0 0 / 6%) 0px 2px 4px, rgb(0 0 0 / 5%) 0px 0.5px 1px;
73
+ --transform-selected: translate3d(0px, -1px, 0px);
74
+
75
+ --content-width: 50rem;
76
+ --navigation-width: 300px;
77
+ --grid-gap: 1rem;
78
+ --grid-gap-s: 0.4rem;
79
+
80
+ /* Calculate the mobile width by removing l/r columns */
81
+ --content-width-mobile: calc(100vw - 1rem);
58
82
 
59
- /* Calculate the mobile width by removing l/r columns and grid gap */
60
- --content-width-mobile: calc(100vw - (1rem * 2));
83
+ /* Search variables */
84
+ --search-height: 2rem;
85
+ --search-dropdown-height: 65vh;
86
+ --search-dropdown-duration: 0.2s;
61
87
  }
62
88
 
63
89
  @media (prefers-color-scheme: dark) {
64
90
  :root {
65
- --fore: #ccc;
66
- --fore-headings: #cce;
67
- --aft: #333;
68
-
69
- --fore-link: #abb9ef;
70
- --fore-link-alt: #abb9ef;
91
+ --fore: #DFF;
92
+ --aft: #233;
93
+ --aft-image: #DDD;
94
+
95
+ --fore-link: #AFF;
96
+ --fore-link-alt: #FF0;
71
97
  --aft-link-alt: #232323;
72
98
 
73
- --fore-head: #ccc;
74
- --aft-head: #222;
75
- --icon-head: #abb9ef;
76
-
77
- --fore-breadcrumb: #ccc;
78
- --aft-breadcrumb: #2c2c2c;
79
-
80
- --link-head: #abb9ef;
81
- --link-alt-head: #6580ed;
99
+ --fore-input: #var(--fore);
100
+ --aft-input: var(--aft);
82
101
 
83
- --fore-block: #ccc;
84
- --aft-block: #111;
85
- --icon-block: #abb9ef;
102
+ --fore-block: #DFF;
103
+ --aft-block: #011;
104
+ --icon-block: #FF0;
86
105
 
87
- --fore-table-head: #ccc;
88
- --aft-table-head: #222;
89
- --fore-table-row-odd: #ccc;
90
- --aft-table-row-odd: #333;
91
- --fore-table-row-even: #ccc;
92
- --aft-table-row-even: #444;
106
+ --fore-table-head: #DFF;
107
+ --aft-table-head: #244;
108
+ --fore-table-row-odd: #DFF;
109
+ --aft-table-row-odd: #355;
110
+ --fore-table-row-even: #DFF;
111
+ --aft-table-row-even: #466;
93
112
  }
94
113
  }
package/src/config.ts CHANGED
@@ -33,6 +33,11 @@ const SITE: Site = {
33
33
  month: 'long',
34
34
  day: 'numeric',
35
35
  },
36
+ shortDateOptions: {
37
+ year: 'numeric',
38
+ month: 'short',
39
+ day: 'numeric',
40
+ },
36
41
  cacheMaxAge: 200,
37
42
  featureFlags: {
38
43
  stickyNav: { top: 100 },
@@ -45,8 +50,7 @@ const SITE: Site = {
45
50
  },
46
51
  images: {
47
52
  // Generated using https://ausi.github.io/respimagelint/
48
- contentSize:
49
- '(min-width: 1280px) 668px, (min-width: 880px) calc(72.11vw - 241px), calc(100vw - 64px)',
53
+ contentSize: '(min-width: 1280px) 668px, (min-width: 880px) calc(72.11vw - 241px), calc(100vw - 64px)',
50
54
  listerSize:
51
55
  '(min-width: 1300px) 350px, (min-width: 880px) calc(34.25vw - 88px), (min-width: 700px) 50vw, calc(100vw - 32px)',
52
56
  authorSize: '50px',
@@ -62,7 +66,9 @@ const OPEN_GRAPH = {
62
66
  };
63
67
 
64
68
  const HEADER_SCRIPTS = `
65
- <!-- HEADER SCRIPTS -->
69
+ <meta name="copyright" content="Steve Fenton">
70
+ <link rel="preload" href="/css/AtkinsonHyperlegibleNext-Bold.otf" as="font" crossorigin>
71
+ <link rel="preload" href="/css/AtkinsonHyperlegibleNext-Regular.otf" as="font" crossorigin>
66
72
  `.trim();
67
73
 
68
74
  export { SITE, OPEN_GRAPH, HEADER_SCRIPTS };
@@ -4,16 +4,20 @@
4
4
  import { Accelerator } from 'astro-accelerator-utils';
5
5
  import type { Frontmatter } from 'astro-accelerator-utils/types/Frontmatter';
6
6
  import { SITE } from '@config';
7
- import { Translations, Lang } from '@util/Languages';;
7
+ import { Translations, Lang } from '@util/Languages';
8
+ import { getImageInfo } from '@util/custom-markdown.mjs';
9
+ import ReadingTime from '@components/ReadingTime.astro';
8
10
 
9
11
  const accelerator = new Accelerator(SITE);
10
- const stats = new accelerator.statistics('accelerator/components/AuthorsMini.astro');
12
+ const stats = new accelerator.statistics(
13
+ 'accelerator/components/AuthorsMini.astro'
14
+ );
11
15
  stats.start();
12
16
 
13
17
  // Properties
14
18
  type Props = {
15
- lang: string;
16
- frontmatter: Frontmatter;
19
+ lang: string;
20
+ frontmatter: Frontmatter;
17
21
  };
18
22
  const { lang, frontmatter } = Astro.props satisfies Props;
19
23
 
@@ -22,29 +26,63 @@ const _ = Lang(lang);
22
26
 
23
27
  // Logic
24
28
  const authorList = accelerator.authors.forPost(frontmatter);
29
+ const dateToShow =
30
+ frontmatter.modDate == null ? frontmatter.pubDate : frontmatter.modDate;
31
+
32
+ // Get image info
33
+ const authorImage = authorList?.image?.src
34
+ ? getImageInfo(authorList.image.src, 'author-image', SITE.images.authorSize)
35
+ : null;
25
36
 
26
37
  stats.stop();
27
38
  ---
28
- {authorList.writers.length > 0 &&
29
- <div class="post-meta">
30
- <div class="author-info">
31
- <span>{ _(Translations.post.written_by) + ' ' }
32
- {authorList.mainAuthor &&
33
- <span>{ authorList.mainAuthor.frontmatter.title }</span>
34
- }{authorList.contributors.map((writer) => (
35
- <span>, </span><span>{ writer.frontmatter.title }</span>
36
- ))}<br />
37
- {frontmatter.modDate == null &&
38
- <time datetime={ frontmatter.pubDate.toString() }>
39
- { accelerator.dateFormatter.formatDate(frontmatter.pubDate, lang) }
40
- </time>
41
- }
42
- {frontmatter.modDate != null &&
43
- <time datetime={ frontmatter.modDate.toString() }>
44
- { accelerator.dateFormatter.formatDate(frontmatter.modDate, lang) }
45
- </time>
46
- }
47
- </span>
48
- </div>
49
- </div>
39
+
40
+ {
41
+ authorList.writers.length > 0 && (
42
+ <div class="post-meta mini">
43
+ <div class="author-info">
44
+ {authorImage && (
45
+ <img
46
+ srcset={authorImage.srcset}
47
+ sizes={authorImage.sizes}
48
+ src={authorImage.src}
49
+ alt={authorList?.image?.alt}
50
+ class={authorImage.class}
51
+ width={authorImage.metadata?.width}
52
+ height={authorImage.metadata?.height}
53
+ />
54
+ )}
55
+ {authorList.mainAuthor && (
56
+ <a
57
+ href={
58
+ accelerator.urlFormatter.formatAddress(
59
+ authorList.mainAuthor.url
60
+ ) + '1/'
61
+ }
62
+ class="author-name">
63
+ {authorList.mainAuthor.frontmatter.title}
64
+ </a>
65
+ )}
66
+ {authorList.contributors.map((writer) => (
67
+ <a
68
+ href={
69
+ accelerator.urlFormatter.formatAddress(writer.url) +
70
+ '1/'
71
+ }
72
+ class="contributor-name">
73
+ {writer.frontmatter.title}
74
+ </a>
75
+ ))}
76
+ <time
77
+ class="post-date"
78
+ datetime={dateToShow.toString()}
79
+ set:html={accelerator.dateFormatter.formatShortDate(
80
+ dateToShow,
81
+ lang
82
+ )}
83
+ />
84
+ <ReadingTime lang={lang} frontmatter={frontmatter} />
85
+ </div>
86
+ </div>
87
+ )
50
88
  }
@@ -0,0 +1,44 @@
1
+ ---
2
+ // warning: This file is overwritten by Astro Accelerator
3
+
4
+ import { Accelerator } from 'astro-accelerator-utils';
5
+ import type { Frontmatter } from 'astro-accelerator-utils/types/Frontmatter';
6
+ import { SITE } from '@config';
7
+ import { Translations, Lang } from '@util/Languages';
8
+
9
+ const accelerator = new Accelerator(SITE);
10
+ const stats = new accelerator.statistics(
11
+ 'accelerator/components/ReadingTime.astro'
12
+ );
13
+ stats.start();
14
+
15
+ // Properties
16
+ type Props = {
17
+ lang: string;
18
+ frontmatter: Frontmatter;
19
+ };
20
+ const { lang, frontmatter } = Astro.props satisfies Props;
21
+
22
+ // Language
23
+ const _ = Lang(lang);
24
+
25
+ // Logic
26
+ const readingTimeText =
27
+ frontmatter?.readingTime === 1
28
+ ? _(Translations.post.reading_time_one_minute).replace(
29
+ '{n}',
30
+ frontmatter.readingTime
31
+ )
32
+ : _(Translations.post.reading_time_many_minutes).replace(
33
+ '{n}',
34
+ frontmatter.readingTime
35
+ );
36
+
37
+ stats.stop();
38
+ ---
39
+
40
+ {
41
+ frontmatter?.readingTime && (
42
+ <span class="reading-time" set:html={readingTimeText} />
43
+ )
44
+ }
@@ -1,116 +1,135 @@
1
1
  ---
2
2
  // warning: This file is overwritten by Astro Accelerator
3
3
 
4
- import { Accelerator, PostFiltering } from "astro-accelerator-utils";
5
- import type { Frontmatter } from "astro-accelerator-utils/types/Frontmatter";
6
- import { getImageInfo } from "@util/custom-markdown.mjs";
7
- import { SITE } from "@config";
8
- import Head from "@components/HtmlHead.astro";
9
- import Header from "@components/Header.astro";
10
- import Footer from "@components/Footer.astro";
11
- import Copyright from "@components/Copyright.astro";
12
- import SkipLinks from "@components/SkipLinks.astro";
13
- import Breadcrumbs from "@components/Breadcrumbs.astro";
14
- import Navigation from "@components/Navigation.astro";
15
- import TableOfContents from "@components/TableOfContents.astro";
16
- import Authors from "@components/Authors.astro";
17
- import Taxonomy from "@components/Taxonomy.astro";
18
- import Related from "@components/Related.astro";
4
+ import { Accelerator, PostFiltering } from 'astro-accelerator-utils';
5
+ import type { Frontmatter } from 'astro-accelerator-utils/types/Frontmatter';
6
+ import { getImageInfo } from '@util/custom-markdown.mjs';
7
+ import { SITE } from '@config';
8
+ import Head from '@components/HtmlHead.astro';
9
+ import Header from '@components/Header.astro';
10
+ import Footer from '@components/Footer.astro';
11
+ import Copyright from '@components/Copyright.astro';
12
+ import SkipLinks from '@components/SkipLinks.astro';
13
+ import Breadcrumbs from '@components/Breadcrumbs.astro';
14
+ import Navigation from '@components/Navigation.astro';
15
+ import TableOfContents from '@components/TableOfContents.astro';
16
+ import Authors from '@components/Authors.astro';
17
+ import AuthorsMini from '@components/AuthorsMini.astro';
18
+ import Taxonomy from '@components/Taxonomy.astro';
19
+ import Related from '@components/Related.astro';
19
20
 
20
21
  const accelerator = new Accelerator(SITE);
21
- const stats = new accelerator.statistics("accelerator/layouts/Default.astro");
22
+ const stats = new accelerator.statistics('accelerator/layouts/Default.astro');
22
23
  stats.start();
23
24
 
24
25
  type Props = {
25
- frontmatter: Frontmatter;
26
- headings: { depth: number; slug: string; text: string }[];
27
- breadcrumbs?: { url: string; title: string; ariaCurrent?: string }[] | null;
26
+ frontmatter: Frontmatter;
27
+ headings: { depth: number; slug: string; text: string }[];
28
+ breadcrumbs?: { url: string; title: string; ariaCurrent?: string }[] | null;
28
29
  };
29
- const { frontmatter, headings, breadcrumbs } = Astro.props satisfies Props;
30
+ const { frontmatter, headings, breadcrumbs, data } =
31
+ Astro.props satisfies Props;
30
32
 
31
33
  const lang = frontmatter.lang ?? SITE.default.lang;
32
34
  const textDirection = frontmatter.dir ?? SITE.default.dir;
33
35
 
34
36
  // Logic
35
37
  const metaImage = frontmatter.bannerImage
36
- ? getImageInfo(frontmatter.bannerImage.src, "", SITE.images.contentSize)
37
- : null;
38
+ ? getImageInfo(frontmatter.bannerImage.src, '', SITE.images.contentSize)
39
+ : null;
38
40
 
39
41
  const title = await accelerator.markdown.getInlineHtmlFrom(
40
- frontmatter.title ?? SITE.title
42
+ frontmatter.title ?? SITE.title
41
43
  );
42
44
  const subtitle = frontmatter.subtitle
43
- ? await accelerator.markdown.getInlineHtmlFrom(frontmatter.subtitle)
44
- : null;
45
+ ? await accelerator.markdown.getInlineHtmlFrom(frontmatter.subtitle)
46
+ : null;
45
47
 
46
48
  const site_url = SITE.url;
47
49
  const site_features = SITE.featureFlags;
48
50
  const search =
49
- accelerator.posts.all().filter(PostFiltering.isSearch).shift() ?? null;
51
+ accelerator.posts.all().filter(PostFiltering.isSearch).shift() ?? null;
50
52
  const searchUrl = search && accelerator.urlFormatter.formatAddress(search.url);
51
53
  const isSearchPage =
52
- accelerator.urlFormatter.formatAddress(Astro.url.pathname) === searchUrl;
54
+ accelerator.urlFormatter.formatAddress(Astro.url.pathname) === searchUrl;
53
55
  const showSearch = !isSearchPage;
54
56
 
55
57
  stats.stop();
56
58
  ---
57
59
 
58
60
  <html dir={textDirection} lang={lang} class="initial">
59
- <Head frontmatter={frontmatter} headings={headings} lang={lang} />
60
- <body>
61
- <SkipLinks frontmatter={frontmatter} headings={headings} lang={lang} />
62
- <Header
63
- frontmatter={frontmatter}
64
- headings={headings}
65
- lang={lang}
66
- showSearch={showSearch}
67
- />
68
- <Breadcrumbs
69
- frontmatter={frontmatter}
70
- headings={headings}
71
- lang={lang}
72
- breadcrumbs={breadcrumbs}
73
- />
74
- <div class="content-group">
75
- <main id="site-main">
76
- <article itemscope itemtype="https://schema.org/Article">
77
- <header>
78
- <h1 itemprop="name headline"><Fragment set:html={title} /></h1>
79
- {
80
- subtitle && (
81
- <p>
82
- <Fragment set:html={subtitle} />
83
- </p>
84
- )
85
- }
86
- </header>
87
- <div class="page-content anim-show-parent" itemprop="articleBody">
88
- <TableOfContents
89
- frontmatter={frontmatter}
90
- headings={headings}
91
- lang={lang}
61
+ <Head frontmatter={frontmatter} headings={headings} lang={lang} />
62
+ <body>
63
+ <SkipLinks frontmatter={frontmatter} headings={headings} lang={lang} />
64
+ <Header
65
+ frontmatter={frontmatter}
66
+ headings={headings}
67
+ lang={lang}
68
+ showSearch={showSearch}
69
+ />
70
+ <Breadcrumbs
71
+ frontmatter={frontmatter}
72
+ headings={headings}
73
+ lang={lang}
74
+ breadcrumbs={breadcrumbs}
75
+ />
76
+ <div class="content-group">
77
+ <main id="site-main">
78
+ <article itemscope itemtype="https://schema.org/Article">
79
+ <header>
80
+ <h1 itemprop="name headline">
81
+ <Fragment set:html={title} />
82
+ </h1>
83
+ {
84
+ subtitle && (
85
+ <p>
86
+ <Fragment set:html={subtitle} />
87
+ </p>
88
+ )
89
+ }
90
+ </header>
91
+ <div
92
+ class="page-content anim-show-parent"
93
+ itemprop="articleBody">
94
+ <AuthorsMini frontmatter={frontmatter} lang={lang} />
95
+ <TableOfContents
96
+ frontmatter={frontmatter}
97
+ headings={headings}
98
+ lang={lang}
99
+ />
100
+ <slot />
101
+ <Authors frontmatter={frontmatter} lang={lang} />
102
+ <Taxonomy frontmatter={frontmatter} lang={lang} />
103
+ <Related
104
+ frontmatter={frontmatter}
105
+ headings={headings}
106
+ lang={lang}
107
+ />
108
+ {
109
+ metaImage && (
110
+ <meta
111
+ itemprop="image"
112
+ content={metaImage.src}
113
+ />
114
+ )
115
+ }
116
+ </div>
117
+ </article>
118
+ </main>
119
+ <Navigation lang={lang} />
120
+ </div>
121
+ <Footer frontmatter={frontmatter} headings={headings} lang={lang}>
122
+ <Copyright
123
+ frontmatter={frontmatter}
124
+ headings={headings}
125
+ lang={lang}
92
126
  />
93
- <slot />
94
- <Authors frontmatter={frontmatter} lang={lang} />
95
- <Taxonomy frontmatter={frontmatter} lang={lang} />
96
- <Related
97
- frontmatter={frontmatter}
98
- headings={headings}
99
- lang={lang}
100
- />
101
- {metaImage && <meta itemprop="image" content={metaImage.src} />}
102
- </div>
103
- </article>
104
- </main>
105
- <Navigation lang={lang} />
106
- </div>
107
- <Footer frontmatter={frontmatter} headings={headings} lang={lang}>
108
- <Copyright frontmatter={frontmatter} headings={headings} lang={lang} />
109
- </Footer>
110
- <script define:vars={{ site_url, site_features }}>
111
- window.site_url = site_url;
112
- window.site_features = site_features;
113
- </script>
114
- <script src={SITE.subfolder + "/js/main.js"} type="module" async></script>
115
- </body>
127
+ </Footer>
128
+ <script define:vars={{ site_url, site_features }}>
129
+ window.site_url = site_url;
130
+ window.site_features = site_features;
131
+ </script>
132
+ <script src={SITE.subfolder + '/js/main.js'} type="module" async
133
+ ></script>
134
+ </body>
116
135
  </html>
@@ -62,6 +62,12 @@
62
62
  },
63
63
  "last_modified": {
64
64
  "en": "Revised"
65
+ },
66
+ "reading_time_one_minute": {
67
+ "en": "{n} min read"
68
+ },
69
+ "reading_time_many_minutes": {
70
+ "en": "{n} min read"
65
71
  }
66
72
  },
67
73
  "author": {
@@ -0,0 +1,18 @@
1
+ /** @format */
2
+
3
+ import { toString } from 'mdast-util-to-string';
4
+
5
+ /**
6
+ * Remark plugin for calculating reading time
7
+ */
8
+ export function readingTime() {
9
+ return function (tree, { data }) {
10
+ const wordsPerMinute = 200;
11
+ const textOnPage = toString(tree);
12
+ const readingTime = Math.ceil(
13
+ textOnPage.split(' ').length / wordsPerMinute
14
+ );
15
+
16
+ data.astro.frontmatter.readingTime = readingTime;
17
+ };
18
+ }