@mdn/fred 1.5.0 → 1.6.0

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.
Files changed (106) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/components/homepage-body/server.js +5 -0
  3. package/components/placement-top/element.js +3 -5
  4. package/components/recently-visited/element.css +35 -0
  5. package/components/recently-visited/element.js +26 -0
  6. package/components/recently-visited/index.js +64 -0
  7. package/components/record-visit/element.js +34 -0
  8. package/components/writer-toolbar/server.js +3 -0
  9. package/out/service-worker.js +1 -1
  10. package/out/service-worker.js.map +1 -1
  11. package/out/static/client/{3132.31660ef023aedecd.js → 3132.4c9442f0ff50faf5.js} +19 -19
  12. package/out/static/client/{3132.31660ef023aedecd.js.map → 3132.4c9442f0ff50faf5.js.map} +1 -1
  13. package/out/static/client/3330.4148ebc5659cafd0.js +2 -0
  14. package/out/static/client/3330.4148ebc5659cafd0.js.map +1 -0
  15. package/out/static/client/486.bb14d2f437221509.js +5 -0
  16. package/out/static/client/486.bb14d2f437221509.js.map +1 -0
  17. package/out/static/client/9566.e7da9862e9ae2e3f.js +2 -0
  18. package/out/static/client/9566.e7da9862e9ae2e3f.js.map +1 -0
  19. package/out/static/client/{index.d61d794e5ecbd37a.js → index.1fdf341dd8b9ed94.js} +4 -4
  20. package/out/static/client/index.1fdf341dd8b9ed94.js.map +1 -0
  21. package/out/static/client/{runtime.35c4249bd039427b.js → runtime.45841d40e5b5e1ef.js} +2 -2
  22. package/out/static/client/runtime.45841d40e5b5e1ef.js.map +1 -0
  23. package/out/static/client/stats.json +255 -255
  24. package/out/static/client/{styles-a11y-menu.2ceb769da0120261.js → styles-a11y-menu.ce2587e83b9d2135.js} +1 -1
  25. package/out/static/client/{styles-advertising.7adabd576561f3e6.js → styles-advertising.ee8a14c6c67283c3.js} +1 -1
  26. package/out/static/client/{styles-article-footer.5c9b71d2d3395a7c.js → styles-article-footer.4d5b2d9b056cde59.js} +1 -1
  27. package/out/static/client/{styles-banner.9d224da378ce969d.js → styles-banner.8fd28aa89146dbdb.js} +1 -1
  28. package/out/static/client/styles-baseline-indicator.36106be6ca127595.js +1 -0
  29. package/out/static/client/{styles-blog-index.e7af7243aac02887.js → styles-blog-index.d6e232d7b78e732b.js} +1 -1
  30. package/out/static/client/{styles-blog-post.63e8c3e251da4ef9.js → styles-blog-post.a97f45d578b9c6d7.js} +1 -1
  31. package/out/static/client/{styles-breadcrumbs-bar.7490a9d0d1211982.js → styles-breadcrumbs-bar.a0c9f135ff00dbf8.js} +1 -1
  32. package/out/static/client/{styles-breadcrumbs.cc7291252773154c.js → styles-breadcrumbs.470e2141b512134e.js} +1 -1
  33. package/out/static/client/{styles-button.7e41bfdbe8042273.js → styles-button.38e3b1ebb5fd2e15.js} +1 -1
  34. package/out/static/client/{styles-content-section.25c29d94b128761d.js → styles-content-section.e068d5efdd83eb2a.js} +1 -1
  35. package/out/static/client/styles-contributor-spotlight.2d83d588fd4f4e47.js +1 -0
  36. package/out/static/client/{styles-curriculum-about.6bc1a13e4fa9f39a.js → styles-curriculum-about.37621a5a4fc4992f.js} +1 -1
  37. package/out/static/client/styles-curriculum-default.285a1e351d549b93.js +1 -0
  38. package/out/static/client/styles-curriculum-landing.109f492769f6c7a1.js +1 -0
  39. package/out/static/client/{styles-curriculum-module.a7bed396f12c806d.js → styles-curriculum-module.1fa90442cce8eecc.js} +1 -1
  40. package/out/static/client/styles-curriculum-overview.a51e5d26a3bf85c3.js +1 -0
  41. package/out/static/client/{styles-featured-articles.0cf4e007e6b328f8.js → styles-featured-articles.d6ffde752d8e9c24.js} +1 -1
  42. package/out/static/client/{styles-footer.ffa197667db94c60.js → styles-footer.6b2237415fa37b9b.js} +1 -1
  43. package/out/static/client/{styles-generic-about.49dfdc1457f9ef37.js → styles-generic-about.c7b0920661ae0e65.js} +1 -1
  44. package/out/static/client/{styles-generic-community.a9b56c9e9a77c370.js → styles-generic-community.270a194f0dfb292e.js} +1 -1
  45. package/out/static/client/{styles-generic-content.b9df075920437e8c.js → styles-generic-content.ddbfc46464be8713.js} +1 -1
  46. package/out/static/client/{styles-generic-layout.a2e6413657fae615.js → styles-generic-layout.49ecdb1edca3cff7.js} +1 -1
  47. package/out/static/client/{styles-generic-sidebar.75bca0c7cfc13c23.js → styles-generic-sidebar.401526542a975971.js} +1 -1
  48. package/out/static/client/{styles-generic-toc.f6feb3d24a0086c8.js → styles-generic-toc.02c1d93c8dd2c206.js} +1 -1
  49. package/out/static/client/styles-global.4031cdde644ed6ce.css +2 -0
  50. package/out/static/client/{styles-global.684fd2c5254c94b8.css.map → styles-global.4031cdde644ed6ce.css.map} +1 -1
  51. package/out/static/client/{styles-global.f17e574d10066602.js → styles-global.d954bf3cd4308e10.js} +1 -1
  52. package/out/static/client/{styles-heading-anchor.b8909454f752b8ed.js → styles-heading-anchor.af0af69ba0ce3837.js} +1 -1
  53. package/out/static/client/{styles-homepage-body.992e8c3030679ed3.js → styles-homepage-body.fc9b3c01cb6239db.js} +1 -1
  54. package/out/static/client/styles-homepage-contributor-spotlight.678b81ccf8c9585b.js +1 -0
  55. package/out/static/client/{styles-homepage-footer.366c0e48a34c6e0a.js → styles-homepage-footer.148e1ae4815a95c5.js} +1 -1
  56. package/out/static/client/{styles-homepage-header.c19924571767d333.js → styles-homepage-header.bde2181288c5bdc5.js} +1 -1
  57. package/out/static/client/{styles-homepage-hero.d5d84e6ccf60912f.js → styles-homepage-hero.a1e69d4935421230.js} +1 -1
  58. package/out/static/client/{styles-homepage.046a3e7acc704ffb.js → styles-homepage.4dac740f0935bb20.js} +1 -1
  59. package/out/static/client/{styles-latest-news.b8bc34eb2b7059f3.js → styles-latest-news.5af4f6c5549190cc.js} +1 -1
  60. package/out/static/client/{styles-left-sidebar.6252b35503f4bad5.js → styles-left-sidebar.1bd4c9f57edfa21d.js} +1 -1
  61. package/out/static/client/{styles-logo.c3a8eb2d0c492233.js → styles-logo.e6f047480d8b413c.js} +1 -1
  62. package/out/static/client/{styles-mandala.79befc40612d83e2.js → styles-mandala.85aa0917c5ded149.js} +1 -1
  63. package/out/static/client/{styles-menu.086320c17cbb4b04.js → styles-menu.a61ce9773751f1d4.js} +1 -1
  64. package/out/static/client/{styles-navigation.e41bd6f01abcff92.js → styles-navigation.feedffa9c6952cbe.js} +1 -1
  65. package/out/static/client/{styles-not-found.7c8c5b9a0e19b8a9.js → styles-not-found.82bfa29eee2c87db.js} +1 -1
  66. package/out/static/client/styles-observatory-landing.2a4b2c96812f32b6.js +1 -0
  67. package/out/static/client/styles-observatory-results.3dfae2ffbd96cfae.js +1 -0
  68. package/out/static/client/{styles-page-layout.25d000b0743f4016.js → styles-page-layout.c5c05df3fe53f77b.js} +1 -1
  69. package/out/static/client/{styles-pagination.419ec2aa3d5c71a7.js → styles-pagination.ad079f4927bac44a.js} +1 -1
  70. package/out/static/client/{styles-playground.8872c57657435fd3.js → styles-playground.4364c516f6615f6f.js} +1 -1
  71. package/out/static/client/styles-recent-contributions.030603cc5127700a.js +1 -0
  72. package/out/static/client/{styles-reference-layout.80c4db43006c4b34.js → styles-reference-layout.11f35dfd7cb7f5fc.js} +1 -1
  73. package/out/static/client/{styles-reference-toc.36356f60a623ac90.js → styles-reference-toc.3453bdb696f82a2c.js} +1 -1
  74. package/out/static/client/{styles-sandbox.96878ad6e02a855b.js → styles-sandbox.4c33dc3bc0f1eea2.js} +1 -1
  75. package/out/static/client/{styles-site-search.20078a00977a55aa.js → styles-site-search.01a967c382d8da1f.js} +1 -1
  76. package/out/static/client/{styles-translation-banner.a66d4ad418df4023.js → styles-translation-banner.4d7f6010548995e0.js} +1 -1
  77. package/out/static/client/{styles-writer-toolbar.8bd519dc7b52b67b.js → styles-writer-toolbar.2e3fade0db754b72.js} +1 -1
  78. package/out/static/client/{styles.609dbfdb35b7eee7.js → styles.5cb6809f960cb6d5.js} +2 -2
  79. package/out/static/client/{styles.609dbfdb35b7eee7.js.map → styles.5cb6809f960cb6d5.js.map} +1 -1
  80. package/out/static/legacy/asset-manifest.json +5 -5
  81. package/out/static/legacy/{index.d7733ed68102743e.html → index.ce4e2073f6fcdcde.html} +1 -1
  82. package/out/static/legacy/{index.5a039200ae9a358a.js → index.f8971c6fcd83fc71.js} +3 -3
  83. package/out/static/legacy/{index.5a039200ae9a358a.js.map → index.f8971c6fcd83fc71.js.map} +1 -1
  84. package/out/static/legacy/stats.json +13 -13
  85. package/out/static/legacy/{yari.a53de09ad69cd193.js → yari.87de8673af6079c0.js} +3 -3
  86. package/out/static/legacy/{yari.a53de09ad69cd193.js.map → yari.87de8673af6079c0.js.map} +1 -1
  87. package/out/static/ssr/index.js +39 -32
  88. package/out/static/ssr/index.js.map +1 -1
  89. package/out/static/ssr/stats.json +4 -4
  90. package/package.json +8 -8
  91. package/types/element-map.d.ts +2 -0
  92. package/out/static/client/index.d61d794e5ecbd37a.js.map +0 -1
  93. package/out/static/client/runtime.35c4249bd039427b.js.map +0 -1
  94. package/out/static/client/styles-baseline-indicator.f8ef541b7fc98d85.js +0 -1
  95. package/out/static/client/styles-contributor-spotlight.ddb49136aac4d2f2.js +0 -1
  96. package/out/static/client/styles-curriculum-default.a267a3f808f44b7b.js +0 -1
  97. package/out/static/client/styles-curriculum-landing.e3772cfb8fda5a32.js +0 -1
  98. package/out/static/client/styles-curriculum-overview.59ca99c0a0d2603d.js +0 -1
  99. package/out/static/client/styles-global.684fd2c5254c94b8.css +0 -2
  100. package/out/static/client/styles-homepage-contributor-spotlight.90291e9be7f332cc.js +0 -1
  101. package/out/static/client/styles-observatory-landing.d3534bcc6875ab9f.js +0 -1
  102. package/out/static/client/styles-observatory-results.c98d9c0afb2ccbbe.js +0 -1
  103. package/out/static/client/styles-recent-contributions.5ef28ac6e9429ebb.js +0 -1
  104. /package/out/static/client/{index.d61d794e5ecbd37a.js.LICENSE.txt → index.1fdf341dd8b9ed94.js.LICENSE.txt} +0 -0
  105. /package/out/static/legacy/{index.5a039200ae9a358a.js.LICENSE.txt → index.f8971c6fcd83fc71.js.LICENSE.txt} +0 -0
  106. /package/out/static/legacy/{yari.a53de09ad69cd193.js.LICENSE.txt → yari.87de8673af6079c0.js.LICENSE.txt} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.6.0](https://github.com/mdn/fred/compare/v1.5.0...v1.6.0) (2025-10-01)
4
+
5
+
6
+ ### Features
7
+
8
+ * **writer-mode:** add recently visited list to homepage ([#821](https://github.com/mdn/fred/issues/821)) ([19d36f2](https://github.com/mdn/fred/commit/19d36f2748f735e838c6825f505ededa6c0db167))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **placement-top:** show fallback if unfilled ([#838](https://github.com/mdn/fred/issues/838)) ([61e2025](https://github.com/mdn/fred/commit/61e20255ac5b942e405f6697a47d0fba504bd7e2))
14
+
15
+
16
+ ### Miscellaneous
17
+
18
+ * **deps-dev:** bump @mdn/browser-compat-data from 7.1.6 to 7.1.8 ([#836](https://github.com/mdn/fred/issues/836)) ([a08b60f](https://github.com/mdn/fred/commit/a08b60f5e6adce641862416bdf0d3c95ee25eb7d))
19
+ * **deps-dev:** bump @mdn/browser-compat-data from 7.1.8 to 7.1.9 ([#844](https://github.com/mdn/fred/issues/844)) ([446f19b](https://github.com/mdn/fred/commit/446f19b225d62611575d5bfa8fe67dbc23b00ed6))
20
+ * **deps-dev:** bump the dev group with 3 updates ([#824](https://github.com/mdn/fred/issues/824)) ([50bc063](https://github.com/mdn/fred/commit/50bc063d14612c78c2800701fa1268427cd4eb2d))
21
+ * **deps:** bump @mdn/rari from 0.1.50 to 0.1.51 ([#841](https://github.com/mdn/fred/issues/841)) ([1609bb0](https://github.com/mdn/fred/commit/1609bb010a2335f5d8c6f90973f1b35ccce9056e))
22
+ * **deps:** promote source-map-support ([#846](https://github.com/mdn/fred/issues/846)) ([467d496](https://github.com/mdn/fred/commit/467d496ac1f22b8d67953d4f607812d6ea9cecbd))
23
+
3
24
  ## [1.5.0](https://github.com/mdn/fred/compare/v1.4.0...v1.5.0) (2025-09-24)
4
25
 
5
26
 
@@ -1,5 +1,7 @@
1
1
  import { html } from "@lit-labs/ssr";
2
+ import { nothing } from "lit";
2
3
 
4
+ import { WRITER_MODE } from "../env/index.js";
3
5
  import { FeaturedArticles } from "../featured-articles/server.js";
4
6
 
5
7
  import { LatestNews } from "../latest-news/server.js";
@@ -12,6 +14,9 @@ export class HomepageBody extends ServerComponent {
12
14
  */
13
15
  render(context) {
14
16
  return html`<div class="homepage-body">
17
+ ${WRITER_MODE && context.localServer
18
+ ? html`<mdn-recently-visited></mdn-recently-visited>`
19
+ : nothing}
15
20
  <section>
16
21
  <h2>${context.l10n`Featured articles`}</h2>
17
22
  ${FeaturedArticles.render(context.hyData.featuredArticles)}
@@ -14,8 +14,6 @@ import styles from "./element.css?lit";
14
14
  * @import { TemplateResult } from "lit";
15
15
  */
16
16
 
17
- const EMPTY = html`<div class="top-placement empty"></div>`;
18
-
19
17
  export class MDNPlacementTop extends PlacementMixin(LitElement) {
20
18
  static styles = styles;
21
19
 
@@ -24,7 +22,7 @@ export class MDNPlacementTop extends PlacementMixin(LitElement) {
24
22
  * @returns {TemplateResult | symbol}
25
23
  */
26
24
  renderInitial() {
27
- return EMPTY;
25
+ return html`<div class="top-placement empty"></div>`;
28
26
  }
29
27
 
30
28
  renderFallback() {
@@ -58,7 +56,7 @@ export class MDNPlacementTop extends PlacementMixin(LitElement) {
58
56
 
59
57
  const data = placementContext?.hpTop || placementContext?.top;
60
58
  if (!data) {
61
- return EMPTY;
59
+ return this.renderFallback();
62
60
  }
63
61
  const {
64
62
  status,
@@ -73,7 +71,7 @@ export class MDNPlacementTop extends PlacementMixin(LitElement) {
73
71
  version,
74
72
  } = data;
75
73
  if (status !== "success") {
76
- return EMPTY;
74
+ return this.renderFallback();
77
75
  }
78
76
  if (!this._viewedUrl) {
79
77
  this._viewedUrl = view;
@@ -0,0 +1,35 @@
1
+ @import url("../global/global.css");
2
+
3
+ h2 {
4
+ font-size: var(--font-size-large);
5
+ font-weight: 500;
6
+ }
7
+
8
+ ul {
9
+ padding: 0;
10
+
11
+ overflow: hidden;
12
+
13
+ list-style: none;
14
+
15
+ border: 1px solid var(--color-border-primary);
16
+ border-radius: 0.5rem;
17
+ }
18
+
19
+ li {
20
+ border-top: 1px solid var(--color-border-primary);
21
+
22
+ &:first-child {
23
+ border-top: none;
24
+ }
25
+ }
26
+
27
+ a {
28
+ display: block;
29
+ padding: 1rem;
30
+ color: var(--color-text-primary);
31
+
32
+ &:not(:hover) {
33
+ text-decoration: none;
34
+ }
35
+ }
@@ -0,0 +1,26 @@
1
+ import { LitElement, html } from "lit";
2
+
3
+ import styles from "./element.css?lit";
4
+
5
+ import { RecentlyVisitedPages } from "./index.js";
6
+
7
+ export class MDNRecentlyVisited extends LitElement {
8
+ static ssr = false;
9
+ static styles = styles;
10
+
11
+ constructor() {
12
+ super();
13
+ this._pages = new RecentlyVisitedPages();
14
+ }
15
+
16
+ render() {
17
+ return html`<h2>Recently visited</h2>
18
+ <ul>
19
+ ${this._pages.map(
20
+ ({ path, title }) => html`<li><a href=${path}>${title}</a></li>`,
21
+ )}
22
+ </ul>`;
23
+ }
24
+ }
25
+
26
+ customElements.define("mdn-recently-visited", MDNRecentlyVisited);
@@ -0,0 +1,64 @@
1
+ export class RecentlyVisitedPages {
2
+ static #key = "recently-visited";
3
+ #pages;
4
+
5
+ constructor() {
6
+ this.#pages = this.#getFromStorage();
7
+ }
8
+
9
+ #getFromStorage() {
10
+ const storage = localStorage.getItem(RecentlyVisitedPages.#key);
11
+ if (storage) {
12
+ let pages;
13
+ try {
14
+ pages = JSON.parse(storage);
15
+ if (Array.isArray(pages)) {
16
+ return pages.map((page) => new RecentlyVisitedPage(page));
17
+ }
18
+ } catch {
19
+ console.error(`Parsing ${RecentlyVisitedPages.#key} failed`);
20
+ }
21
+ }
22
+ return [];
23
+ }
24
+
25
+ #saveToStorage() {
26
+ localStorage.setItem(
27
+ RecentlyVisitedPages.#key,
28
+ JSON.stringify(this.#pages),
29
+ );
30
+ }
31
+
32
+ /**
33
+ * @template T
34
+ * @param {(value: RecentlyVisitedPage, index: number, array: RecentlyVisitedPage[]) => T} callback
35
+ * @returns {T[]}
36
+ */
37
+ map(callback) {
38
+ return this.#pages.map(callback);
39
+ }
40
+
41
+ /**
42
+ * @param {RecentlyVisitedPage} page
43
+ */
44
+ add(page) {
45
+ this.#pages = [
46
+ ...new Map([page, ...this.#pages].map((p) => [p.path, p])).values(),
47
+ ].slice(0, 10);
48
+ this.#saveToStorage();
49
+ }
50
+ }
51
+
52
+ export class RecentlyVisitedPage {
53
+ title = "";
54
+ path = "";
55
+
56
+ /**
57
+ * @param {object} data
58
+ * @param {string} data.title
59
+ * @param {string} data.path
60
+ */
61
+ constructor(data) {
62
+ Object.assign(this, data);
63
+ }
64
+ }
@@ -0,0 +1,34 @@
1
+ import { LitElement } from "lit";
2
+
3
+ import {
4
+ RecentlyVisitedPage,
5
+ RecentlyVisitedPages,
6
+ } from "../recently-visited/index.js";
7
+
8
+ export class MDNRecordVisit extends LitElement {
9
+ static ssr = false;
10
+ static properties = {
11
+ pageTitle: { type: String, attribute: "page-title" },
12
+ };
13
+
14
+ constructor() {
15
+ super();
16
+ /** @type {string | undefined} */
17
+ this.pageTitle;
18
+ }
19
+
20
+ connectedCallback() {
21
+ super.connectedCallback();
22
+ if (this.pageTitle) {
23
+ const visited = new RecentlyVisitedPages();
24
+ visited.add(
25
+ new RecentlyVisitedPage({
26
+ title: this.pageTitle,
27
+ path: location.pathname,
28
+ }),
29
+ );
30
+ }
31
+ }
32
+ }
33
+
34
+ customElements.define("mdn-record-visit", MDNRecordVisit);
@@ -24,6 +24,9 @@ export class WriterToolbar extends ServerComponent {
24
24
  filepath=${`${folder}/${filename}`}
25
25
  ></mdn-writer-open-editor>
26
26
  <mdn-writer-reload></mdn-writer-reload>
27
+ <mdn-record-visit
28
+ page-title=${context.doc.title}
29
+ ></mdn-record-visit>
27
30
  `
28
31
  : nothing}
29
32
  </div>`;