@mdn/fred 2.4.2 → 2.5.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 (84) hide show
  1. package/.nvmrc +1 -1
  2. package/CHANGELOG.md +39 -0
  3. package/README.md +2 -0
  4. package/components/baseline-indicator/server.js +86 -32
  5. package/components/compat-section/server.js +45 -0
  6. package/components/compat-table/utils.js +10 -0
  7. package/components/compat-table-lazy/element.js +2 -5
  8. package/components/content-section/server.js +4 -22
  9. package/components/curriculum/sidebar.css +1 -1
  10. package/components/env/index.js +1 -1
  11. package/components/left-sidebar/server.css +1 -1
  12. package/components/media/index.css +5 -5
  13. package/components/menu/missing-docs.json +0 -1
  14. package/components/outer-layout/server.js +3 -3
  15. package/components/server/index.js +4 -0
  16. package/components/sidebar-filter/sidebar-filterer.js +4 -2
  17. package/components/specifications-list/server.js +72 -0
  18. package/out/service-worker.js +1 -1
  19. package/out/static/client/{251.db6a4b10ef58ad3a.js → 251.f498960ce719d884.js} +6 -6
  20. package/out/static/client/251.f498960ce719d884.js.map +1 -0
  21. package/out/static/client/{3259.767db1f79a406e65.js → 3259.ac8a5539251c647a.js} +2 -2
  22. package/out/static/client/{3259.767db1f79a406e65.js.map → 3259.ac8a5539251c647a.js.map} +1 -1
  23. package/out/static/client/{5408.a0622390fa1726dc.css → 5408.77c9b71d6a5df982.css} +2 -2
  24. package/out/static/client/{5408.a0622390fa1726dc.css.map → 5408.77c9b71d6a5df982.css.map} +1 -1
  25. package/out/static/client/6002.60280d36f6ea71ff.js +167 -0
  26. package/out/static/client/6002.60280d36f6ea71ff.js.map +1 -0
  27. package/out/static/client/6216.2a29b5ce2a1bf6f6.js +2 -0
  28. package/out/static/client/6216.2a29b5ce2a1bf6f6.js.map +1 -0
  29. package/out/static/client/{9127.4debc5342015b0ec.js → 9127.08c4f752c4186007.js} +2 -2
  30. package/out/static/client/{9127.4debc5342015b0ec.js.map → 9127.08c4f752c4186007.js.map} +1 -1
  31. package/out/static/client/{9204.515db9110e143075.js → 9204.f8aa5d9f8a79f3d4.js} +2 -2
  32. package/out/static/client/{9204.515db9110e143075.js.map → 9204.f8aa5d9f8a79f3d4.js.map} +1 -1
  33. package/out/static/client/9324.61778c81f15bcebc.js +26 -0
  34. package/out/static/client/9324.61778c81f15bcebc.js.map +1 -0
  35. package/out/static/client/{9326.6a60853854f7ec9b.css → 9326.431ef0e548c5f096.css} +2 -2
  36. package/out/static/client/{9326.6a60853854f7ec9b.css.map → 9326.431ef0e548c5f096.css.map} +1 -1
  37. package/out/static/client/{index.2d8f328c434a5768.js → index.ae68bec0e2489b62.js} +4 -4
  38. package/out/static/client/index.ae68bec0e2489b62.js.map +1 -0
  39. package/out/static/client/{runtime.fa41b0d4fa762325.js → runtime.5a92d4f860d6d798.js} +2 -2
  40. package/out/static/client/{runtime.fa41b0d4fa762325.js.map → runtime.5a92d4f860d6d798.js.map} +1 -1
  41. package/out/static/client/stats.json +143 -143
  42. package/out/static/client/{styles-blog-post.c03ec8a22f8d4ff6.css → styles-blog-post.d0b92f36d3ccd2ae.css} +2 -2
  43. package/out/static/client/{styles-blog-post.c03ec8a22f8d4ff6.css.map → styles-blog-post.d0b92f36d3ccd2ae.css.map} +1 -1
  44. package/out/static/client/{styles-curriculum-landing.6700bec8f414e4d9.css → styles-curriculum-landing.9b5fbdd11a9d6c5b.css} +2 -2
  45. package/out/static/client/{styles-curriculum-landing.6700bec8f414e4d9.css.map → styles-curriculum-landing.9b5fbdd11a9d6c5b.css.map} +1 -1
  46. package/out/static/client/{styles-featured-articles.b4ecc71ab736bd5b.css → styles-featured-articles.a2c1f1fd278c9256.css} +2 -2
  47. package/out/static/client/{styles-featured-articles.b4ecc71ab736bd5b.css.map → styles-featured-articles.a2c1f1fd278c9256.css.map} +1 -1
  48. package/out/static/client/{styles-generic-about.8fb97dff70bba559.css → styles-generic-about.8856856e6f4b7e46.css} +2 -2
  49. package/out/static/client/{styles-generic-about.8fb97dff70bba559.css.map → styles-generic-about.8856856e6f4b7e46.css.map} +1 -1
  50. package/out/static/client/styles-global.274bf4a7ba3e88ae.css +2 -0
  51. package/out/static/client/{styles-global.356d25ef0f954fc4.css.map → styles-global.274bf4a7ba3e88ae.css.map} +1 -1
  52. package/out/static/client/{styles-global.8b4b213c704a703e.js → styles-global.64aa0c760d2688b4.js} +1 -1
  53. package/out/static/client/{styles-homepage-contributor-spotlight.2bcbb1476c70410c.css → styles-homepage-contributor-spotlight.5dc97e2f6ae1056d.css} +2 -2
  54. package/out/static/client/{styles-homepage-contributor-spotlight.2bcbb1476c70410c.css.map → styles-homepage-contributor-spotlight.5dc97e2f6ae1056d.css.map} +1 -1
  55. package/out/static/client/{styles-latest-news.ef3b9e57333a87bc.css → styles-latest-news.afe0cccaa067269f.css} +2 -2
  56. package/out/static/client/{styles-latest-news.ef3b9e57333a87bc.css.map → styles-latest-news.afe0cccaa067269f.css.map} +1 -1
  57. package/out/static/client/{styles-left-sidebar.6f954e8939555f77.css → styles-left-sidebar.517b9efefbdeed1d.css} +2 -2
  58. package/out/static/client/{styles-left-sidebar.6f954e8939555f77.css.map → styles-left-sidebar.517b9efefbdeed1d.css.map} +1 -1
  59. package/out/static/legacy/6753.072394f4f09652a0.js +27 -0
  60. package/out/static/legacy/6753.072394f4f09652a0.js.map +1 -0
  61. package/out/static/legacy/asset-manifest.json +5 -5
  62. package/out/static/legacy/{index.85161ba7fe682ee8.html → index.c05c933009dda5b3.html} +1 -1
  63. package/out/static/legacy/stats.json +9 -9
  64. package/out/static/legacy/{yari.01d97d56e30935ec.js → yari.e457418f21984506.js} +3 -3
  65. package/out/static/legacy/{yari.01d97d56e30935ec.js.map → yari.e457418f21984506.js.map} +1 -1
  66. package/out/static/ssr/index.js +160 -144
  67. package/out/static/ssr/index.js.map +1 -1
  68. package/out/static/ssr/stats.json +4 -4
  69. package/package.json +16 -10
  70. package/components/specifications-list/index.js +0 -60
  71. package/out/static/client/251.db6a4b10ef58ad3a.js.map +0 -1
  72. package/out/static/client/6216.f526aaf8b3dedd72.js +0 -2
  73. package/out/static/client/6216.f526aaf8b3dedd72.js.map +0 -1
  74. package/out/static/client/718.071765b571e2315c.js +0 -167
  75. package/out/static/client/718.071765b571e2315c.js.map +0 -1
  76. package/out/static/client/9324.9bb064ea7377127e.js +0 -26
  77. package/out/static/client/9324.9bb064ea7377127e.js.map +0 -1
  78. package/out/static/client/index.2d8f328c434a5768.js.map +0 -1
  79. package/out/static/client/styles-global.356d25ef0f954fc4.css +0 -2
  80. package/out/static/legacy/6753.811fcf40c897d487.js +0 -27
  81. package/out/static/legacy/6753.811fcf40c897d487.js.map +0 -1
  82. /package/out/static/client/{index.2d8f328c434a5768.js.LICENSE.txt → index.ae68bec0e2489b62.js.LICENSE.txt} +0 -0
  83. /package/out/static/legacy/{6753.811fcf40c897d487.js.LICENSE.txt → 6753.072394f4f09652a0.js.LICENSE.txt} +0 -0
  84. /package/out/static/legacy/{yari.01d97d56e30935ec.js.LICENSE.txt → yari.e457418f21984506.js.LICENSE.txt} +0 -0
package/.nvmrc CHANGED
@@ -1 +1 @@
1
- v24
1
+ v24.15.0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,44 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.5.0](https://github.com/mdn/fred/compare/v2.4.3...v2.5.0) (2026-04-23)
4
+
5
+
6
+ ### Features
7
+
8
+ * **baseline-indicator:** add renderSimplified method ([#1500](https://github.com/mdn/fred/issues/1500)) ([556412d](https://github.com/mdn/fred/commit/556412d6ac6b5398e773eedd89fa4ae710ad6f43))
9
+ * **bcd:** render links to JSON in simplified HTML ([#1502](https://github.com/mdn/fred/issues/1502)) ([d82fd33](https://github.com/mdn/fred/commit/d82fd33921bea39e23c2b1aae3123848ddae0b5c))
10
+ * **specifications:** render a list in simplified mode ([#1504](https://github.com/mdn/fred/issues/1504)) ([abf1784](https://github.com/mdn/fred/commit/abf17843f6dc0f6a18f6bff6f523255ed74e37b2))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **sidebar-filter:** remove only highlight spans on reset ([#1496](https://github.com/mdn/fred/issues/1496)) ([c647e79](https://github.com/mdn/fred/commit/c647e794552c08f1574545378ba5986699633e7f))
16
+
17
+
18
+ ### Miscellaneous
19
+
20
+ * **deps-dev:** bump @codemirror/view from 6.41.0 to 6.41.1 in the npm-dev group ([#1494](https://github.com/mdn/fred/issues/1494)) ([06be168](https://github.com/mdn/fred/commit/06be168411bf3efe7a38bc6a291e9a91b1b6c309))
21
+ * **deps-dev:** bump @codemirror/view in the npm-dev group ([06be168](https://github.com/mdn/fred/commit/06be168411bf3efe7a38bc6a291e9a91b1b6c309))
22
+ * **deps-dev:** bump npm from 11.6.2 to 11.12.1 ([#1490](https://github.com/mdn/fred/issues/1490)) ([fbc5e9a](https://github.com/mdn/fred/commit/fbc5e9a78d5332ade4f99d931011fc681c653f77))
23
+ * **deps-dev:** bump stylelint from 17.8.0 to 17.9.0 in the npm-dev group ([#1514](https://github.com/mdn/fred/issues/1514)) ([87617be](https://github.com/mdn/fred/commit/87617be8e0f3c712385ccce424edf07756b9bf8c))
24
+ * **deps-dev:** bump stylelint in the npm-dev group ([87617be](https://github.com/mdn/fred/commit/87617be8e0f3c712385ccce424edf07756b9bf8c))
25
+ * **deps-dev:** bump typescript-eslint from 8.58.2 to 8.59.0 in the npm-dev group ([#1499](https://github.com/mdn/fred/issues/1499)) ([b25912c](https://github.com/mdn/fred/commit/b25912ceb942de26ac5df8153317b8de172a4e2c))
26
+ * **deps-dev:** bump typescript-eslint in the npm-dev group ([b25912c](https://github.com/mdn/fred/commit/b25912ceb942de26ac5df8153317b8de172a4e2c))
27
+ * **deps:** bump @mdn/rari from 0.2.19 to 0.2.20 ([#1515](https://github.com/mdn/fred/issues/1515)) ([d292b8a](https://github.com/mdn/fred/commit/d292b8aedf464a17ab7f5a3224fbeaef330ade2e))
28
+ * **transcend:** use TRANSCEND_AIRGAP_URL ([#1497](https://github.com/mdn/fred/issues/1497)) ([5e8a62a](https://github.com/mdn/fred/commit/5e8a62a1437718631ca1ee010e53cda377126a1b))
29
+
30
+ ## [2.4.3](https://github.com/mdn/fred/compare/v2.4.2...v2.4.3) (2026-04-17)
31
+
32
+
33
+ ### Miscellaneous
34
+
35
+ * **deps-dev:** bump @mdn/browser-compat-data from 7.3.11 to 7.3.12 ([#1491](https://github.com/mdn/fred/issues/1491)) ([c135a83](https://github.com/mdn/fred/commit/c135a83e2732bc9342a18ae67f07065a6f9b17cb))
36
+ * **deps-dev:** bump the npm-dev group with 2 updates ([#1484](https://github.com/mdn/fred/issues/1484)) ([f7f1096](https://github.com/mdn/fred/commit/f7f1096c93bfd978176c0edcec9f53d90b66f0e2))
37
+ * **deps-dev:** bump the npm-dev group with 2 updates ([#1489](https://github.com/mdn/fred/issues/1489)) ([f2e1e39](https://github.com/mdn/fred/commit/f2e1e394c7dc1d6be60d9601a5a7bcfaf2ea8b8b))
38
+ * **deps:** bump @mdn/rari from 0.2.17 to 0.2.19 ([#1492](https://github.com/mdn/fred/issues/1492)) ([7693845](https://github.com/mdn/fred/commit/76938450156aea8657f74dfa6d6662fd86950b5e))
39
+ * **media:** reorder width-first in two-part queries ([#1464](https://github.com/mdn/fred/issues/1464)) ([c808c41](https://github.com/mdn/fred/commit/c808c4119d9e08b84fb95ff7da2a53dafc5767e2))
40
+ * **menu:** update menu entries ([#1487](https://github.com/mdn/fred/issues/1487)) ([2065f38](https://github.com/mdn/fred/commit/2065f3885866a63d9007649d7489fa3a346ab3e2))
41
+
3
42
  ## [2.4.2](https://github.com/mdn/fred/compare/v2.4.1...v2.4.2) (2026-04-15)
4
43
 
5
44
 
package/README.md CHANGED
@@ -172,6 +172,8 @@ This issue is tracked upstream: https://github.com/lit/lit/issues/1434
172
172
 
173
173
  Any server component can define a `renderSimplified` method to define the simplified form of that component. When in the top-level `renderSimplified` context, any calls of `ServerComponent.render()` will automatically call the `renderSimplified` method of that component, falling back to the `render` method. This is so we can nest components with a `renderSimplified` method ("simplified components") within ones without.
174
174
 
175
+ Server components also have a `simplifiedMode` property set, which is `true` when rendered from the top-level `renderSimplified` function: this allows a small tweak within a `render` method without having to totally re-implement logic in the `renderSimplified` method.
176
+
175
177
  There shouldn't be standalone simplified components: the nesting of components should be defined by the requirements of the `render` method. `renderSimplified` should only be added to a component which already exists with a `render` method to give a simplified view of it. This is especially important as, in the future, we may need to add options of what is/isn't rendered within `renderSimplified` for use in different contexts (one context may require a sidebar, another may not, for instance).
176
178
 
177
179
  You can preview the rendering locally by setting `FRED_SIMPLE_HTML`:
@@ -51,7 +51,43 @@ export class BaselineIndicator extends ServerComponent {
51
51
  static inlineScript = inlineScript;
52
52
 
53
53
  /**
54
- *
54
+ * @param {string | null | undefined} date
55
+ */
56
+ parseDate(date) {
57
+ const lowDateRange = date?.match(/^([^0-9])/)?.[0];
58
+ return date ? new Date(date.slice(lowDateRange ? 1 : 0)) : undefined;
59
+ }
60
+
61
+ /**
62
+ * @param {import("@fred").Context<import("@rari").DocPage>} context
63
+ * @param {string} level
64
+ * @param {Date} [lowDate]
65
+ */
66
+ getExtraText(context, level, lowDate) {
67
+ return level === "high" && lowDate
68
+ ? context.l10n.raw({
69
+ id: "baseline-high-extra",
70
+ args: {
71
+ date: lowDate.toLocaleDateString(context.locale, {
72
+ year: "numeric",
73
+ month: "long",
74
+ }),
75
+ },
76
+ })
77
+ : level === "low" && lowDate
78
+ ? context.l10n.raw({
79
+ id: "baseline-low-extra",
80
+ args: {
81
+ date: lowDate.toLocaleDateString(DEFAULT_LOCALE, {
82
+ year: "numeric",
83
+ month: "long",
84
+ }),
85
+ },
86
+ })
87
+ : context.l10n("baseline-not-extra");
88
+ }
89
+
90
+ /**
55
91
  * @param {import("@fred").Context<import("@rari").DocPage>} context
56
92
  */
57
93
  render(context) {
@@ -71,11 +107,7 @@ export class BaselineIndicator extends ServerComponent {
71
107
  LOCALIZED_BCD_IDS[context.locale] || LOCALIZED_BCD_IDS[DEFAULT_LOCALE]
72
108
  }`;
73
109
 
74
- const low_date_range = status.baseline_low_date?.match(/^([^0-9])/)?.[0];
75
- const low_date = status.baseline_low_date
76
- ? new Date(status.baseline_low_date.slice(low_date_range ? 1 : 0))
77
- : undefined;
78
-
110
+ const lowDate = this.parseDate(status.baseline_low_date);
79
111
  const level = status.baseline || "not";
80
112
 
81
113
  const feedbackLink = `${SURVEY_URL}?page=${encodeURIComponent(context.url)}&level=${level}`;
@@ -154,7 +186,7 @@ export class BaselineIndicator extends ServerComponent {
154
186
  ? context.l10n(
155
187
  "baseline-indicator-widely-available",
156
188
  )`Widely available`
157
- : low_date?.getFullYear()}
189
+ : lowDate?.getFullYear()}
158
190
  </span>
159
191
  ${status.asterisk && " *"}
160
192
  `}
@@ -191,31 +223,7 @@ export class BaselineIndicator extends ServerComponent {
191
223
  <span class="icon icon-chevron"></span>
192
224
  </summary>
193
225
  <div class="extra">
194
- ${level === "high" && low_date
195
- ? html`<p>
196
- ${context.l10n.raw({
197
- id: "baseline-high-extra",
198
- args: {
199
- date: low_date.toLocaleDateString(context.locale, {
200
- year: "numeric",
201
- month: "long",
202
- }),
203
- },
204
- })}
205
- </p>`
206
- : level === "low" && low_date
207
- ? html`<p>
208
- ${context.l10n.raw({
209
- id: "baseline-low-extra",
210
- args: {
211
- date: low_date.toLocaleDateString(DEFAULT_LOCALE, {
212
- year: "numeric",
213
- month: "long",
214
- }),
215
- },
216
- })}
217
- </p>`
218
- : html`<p>${context.l10n("baseline-not-extra")}</p>`}
226
+ <p>${this.getExtraText(context, level, lowDate)}</p>
219
227
  ${status.asterisk
220
228
  ? html`<p>* ${context.l10n("baseline-asterisk")}</p>`
221
229
  : nothing}
@@ -254,4 +262,50 @@ export class BaselineIndicator extends ServerComponent {
254
262
  </div>
255
263
  </details>`;
256
264
  }
265
+
266
+ /**
267
+ * @param {import("@fred").Context<import("@rari").DocPage>} context
268
+ */
269
+ renderSimplified(context) {
270
+ const { doc } = context;
271
+
272
+ if (!doc) {
273
+ return nothing;
274
+ }
275
+
276
+ const status = doc.baseline;
277
+
278
+ if (!status) {
279
+ return nothing;
280
+ }
281
+
282
+ const lowDate = this.parseDate(status.baseline_low_date);
283
+ const level = status.baseline || "not";
284
+
285
+ return html`<p>
286
+ <strong>
287
+ ${level === "not"
288
+ ? context.l10n(
289
+ "baseline-indicator-limited-availability",
290
+ )`Limited availability`
291
+ : context.l10n("baseline-indicator-baseline")`Baseline`}
292
+ ${level === "high"
293
+ ? context.l10n(
294
+ "baseline-indicator-widely-available",
295
+ )`Widely available`
296
+ : level === "low"
297
+ ? html`${lowDate?.getFullYear()}
298
+ ${context.l10n(
299
+ "baseline-indicator-newly-available",
300
+ )`Newly available`}`
301
+ : nothing}
302
+ ${status.asterisk ? " *" : nothing}
303
+ </strong>
304
+ <br />
305
+ ${this.getExtraText(context, level, lowDate)}
306
+ ${status.asterisk
307
+ ? html`<br />* ${context.l10n("baseline-asterisk")}`
308
+ : nothing}
309
+ </p>`;
310
+ }
257
311
  }
@@ -0,0 +1,45 @@
1
+ import { html } from "@lit-labs/ssr";
2
+ import { nothing } from "lit";
3
+ import { ifDefined } from "lit/directives/if-defined.js";
4
+
5
+ import { queryToUrl } from "../compat-table/utils.js";
6
+ import { HeadingAnchor } from "../heading-anchor/server.js";
7
+ import { ServerComponent } from "../server/index.js";
8
+
9
+ export class CompatSection extends ServerComponent {
10
+ /**
11
+ * @param {import("@fred").Context} _context
12
+ * @param {import("@rari").Compat} section
13
+ */
14
+ render(_context, { id, title, query, isH3 }) {
15
+ const level = isH3 ? 3 : 2;
16
+ return html`<section
17
+ class="content-section"
18
+ aria-labelledby=${ifDefined(id ?? undefined)}
19
+ >
20
+ ${HeadingAnchor.render(level, id ? String(id) : null, String(title))}
21
+ <mdn-compat-table-lazy
22
+ locale="en-US"
23
+ query=${query}
24
+ ></mdn-compat-table-lazy>
25
+ </section>`;
26
+ }
27
+
28
+ /**
29
+ * @param {import("@fred").Context} _context
30
+ * @param {import("@rari").Compat} section
31
+ */
32
+ renderSimplified(_context, { id, title, query, isH3 }) {
33
+ return html`<section
34
+ class="content-section"
35
+ aria-labelledby=${ifDefined(id ?? undefined)}
36
+ >
37
+ ${isH3
38
+ ? nothing
39
+ : HeadingAnchor.render(2, id ? String(id) : null, String(title))}
40
+ <a href=${queryToUrl(query)} target="_blank" rel="noopener"
41
+ ><code>${query}</code></a
42
+ >
43
+ </section>`;
44
+ }
45
+ }
@@ -1,3 +1,5 @@
1
+ import { BCD_BASE_URL } from "../env/index.js";
2
+
1
3
  /**
2
4
  * A list of browsers to be hidden.
3
5
  * @constant {string[]}
@@ -293,3 +295,11 @@ export function getCurrentSupport(support) {
293
295
  // Default (likely never reached).
294
296
  return getFirst(support);
295
297
  }
298
+
299
+ /**
300
+ * Get the URL to the JSON file for a given BCD key
301
+ * @param {string} query
302
+ */
303
+ export function queryToUrl(query) {
304
+ return `${BCD_BASE_URL}/bcd/api/v0/current/${query}.json`;
305
+ }
@@ -8,7 +8,7 @@ import {
8
8
  DEFAULT_LOCALE,
9
9
  ISSUE_METADATA_TEMPLATE,
10
10
  } from "../compat-table/constants.js";
11
- import { BCD_BASE_URL } from "../env/index.js";
11
+ import { queryToUrl } from "../compat-table/utils.js";
12
12
 
13
13
  import styles from "./element.css?lit";
14
14
 
@@ -76,10 +76,7 @@ export class MDNCompatTableLazy extends L10nMixin(LitElement) {
76
76
  _dataTask = new Task(this, {
77
77
  args: () => [this.query],
78
78
  task: async ([query], { signal }) => {
79
- const response = await fetch(
80
- `${BCD_BASE_URL}/bcd/api/v0/current/${query}.json`,
81
- { signal },
82
- );
79
+ const response = await fetch(queryToUrl(query), { signal });
83
80
  if (!response.ok) {
84
81
  console.error("Failed to fetch BCD data:", response);
85
82
 
@@ -2,20 +2,20 @@ import { html } from "@lit-labs/ssr";
2
2
  import { ifDefined } from "lit/directives/if-defined.js";
3
3
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
4
4
 
5
+ import { CompatSection } from "../compat-section/server.js";
5
6
  import { HeadingAnchor } from "../heading-anchor/server.js";
6
7
  import { ServerComponent } from "../server/index.js";
7
- import { SpecificationsList } from "../specifications-list/index.js";
8
+ import { SpecificationsList } from "../specifications-list/server.js";
8
9
 
9
10
  export class ContentSection extends ServerComponent {
10
11
  /**
11
12
  * @param {import("@fred").Context} context
12
13
  * @param {import("@rari").Section} section
13
- * @returns {import("@lit").TemplateResult}
14
14
  */
15
15
  render(context, { type, value }) {
16
16
  switch (type) {
17
17
  case "browser_compatibility": {
18
- return BCD(value);
18
+ return CompatSection.render(context, value);
19
19
  }
20
20
  case "specifications": {
21
21
  return SpecificationsSection(context, value);
@@ -43,24 +43,6 @@ function Prose({ id, title, content, isH3 }) {
43
43
  </section>`;
44
44
  }
45
45
 
46
- /**
47
- * @param {import("@rari").Compat} section
48
- * @returns {import("@lit").TemplateResult}
49
- */
50
- function BCD({ id, title, query, isH3 }) {
51
- const level = isH3 ? 3 : 2;
52
- return html`<section
53
- class="content-section"
54
- aria-labelledby=${ifDefined(id ?? undefined)}
55
- >
56
- ${HeadingAnchor.render(level, id ? String(id) : null, String(title))}
57
- <mdn-compat-table-lazy
58
- locale="en-US"
59
- query=${query}
60
- ></mdn-compat-table-lazy>
61
- </section>`;
62
- }
63
-
64
46
  /**
65
47
  * @param {import("@fred").Context} context
66
48
  * @param {import("@rari").SpecificationSection} section
@@ -72,6 +54,6 @@ function SpecificationsSection(context, { id, title, specifications, isH3 }) {
72
54
  aria-labelledby=${ifDefined(id ?? undefined)}
73
55
  >
74
56
  ${HeadingAnchor.render(level, id ? String(id) : null, String(title))}
75
- ${SpecificationsList(context, specifications)}
57
+ ${SpecificationsList.render(context, specifications)}
76
58
  </section>`;
77
59
  }
@@ -78,7 +78,7 @@
78
78
  }
79
79
 
80
80
  a,
81
- span:not(.highlight-container) {
81
+ span:not(.sidebar-filter-mark-container) {
82
82
  display: inline-flex;
83
83
  padding-block: 0.25rem;
84
84
  }
@@ -50,4 +50,4 @@ export const OBSERVATORY_API_URL = parseString(
50
50
  );
51
51
 
52
52
  // Transcend Consent Management - https://docs.transcend.io/docs/consent
53
- export const TRANSCEND_BUNDLE_ID = parseString("TRANSCEND_BUNDLE_ID", "");
53
+ export const TRANSCEND_AIRGAP_URL = parseString("TRANSCEND_AIRGAP_URL", "");
@@ -115,7 +115,7 @@
115
115
  }
116
116
 
117
117
  a,
118
- span:not(.highlight-container) {
118
+ span:not(.sidebar-filter-mark-container) {
119
119
  display: inline-block;
120
120
  padding-block: 0.25rem;
121
121
  vertical-align: middle;
@@ -2,23 +2,23 @@
2
2
 
3
3
  @custom-media --screen-xsmall (width <= 426px);
4
4
 
5
- @custom-media --screen-small-and-wider (426px < width);
5
+ @custom-media --screen-small-and-wider (width > 426px);
6
6
  @custom-media --screen-small-only (426px < width <= 769px);
7
7
  @custom-media --screen-small-and-narrower (width <= 769px);
8
8
 
9
- @custom-media --screen-medium-and-wider (769px < width);
9
+ @custom-media --screen-medium-and-wider (width > 769px);
10
10
  @custom-media --screen-medium-only (769px < width <= 992px);
11
11
  @custom-media --screen-medium-and-narrower (width <= 992px);
12
12
 
13
- @custom-media --screen-large-and-wider (992px < width);
13
+ @custom-media --screen-large-and-wider (width > 992px);
14
14
  @custom-media --screen-large-only (992px < width <= 1200px);
15
15
  @custom-media --screen-large-and-narrower (width <= 1200px);
16
16
 
17
- @custom-media --screen-xlarge-and-wider (1200px < width);
17
+ @custom-media --screen-xlarge-and-wider (width > 1200px);
18
18
  @custom-media --screen-xlarge-only (1200px < width <= 1441px);
19
19
  @custom-media --screen-xlarge-and-narrower (width <= 1441px);
20
20
 
21
- @custom-media --screen-xxlarge (1441px < width);
21
+ @custom-media --screen-xxlarge (width > 1441px);
22
22
 
23
23
  @custom-media --screen-menu-full (width > 1044px);
24
24
  @custom-media --screen-menu-hamburger (width <= 1044px);
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "es": [
3
3
  "Web/API/Web_Animations_API/Using_the_Web_Animations_API",
4
- "Web/CSS/Guides",
5
4
  "Web/CSS/Guides/Backgrounds_and_borders/Box-shadow_generator",
6
5
  "Web/CSS/Guides/Colors/Applying_color",
7
6
  "Web/CSS/Guides/Colors/Color_mixer",
@@ -6,7 +6,7 @@ import { unsafeHTML } from "lit/directives/unsafe-html.js";
6
6
  import inlineScript from "../../entry.inline.js?source&csp=true";
7
7
  import {
8
8
  ROBOTS_GLOBAL_ALLOW,
9
- TRANSCEND_BUNDLE_ID,
9
+ TRANSCEND_AIRGAP_URL,
10
10
  WRITER_MODE,
11
11
  } from "../env/index.js";
12
12
  import { RUNTIME_ENV, runtimeVariables } from "../env/runtime.js";
@@ -116,12 +116,12 @@ export class OuterLayout extends ServerComponent {
116
116
  fetchpriority="low"
117
117
  />`,
118
118
  )}
119
- ${TRANSCEND_BUNDLE_ID &&
119
+ ${TRANSCEND_AIRGAP_URL &&
120
120
  html`<script
121
121
  data-cfasync="false"
122
122
  data-report-only="on"
123
123
  data-prompt="0"
124
- src=${`https://transcend-cdn.com/cm/${TRANSCEND_BUNDLE_ID}/airgap.js`}
124
+ src=${TRANSCEND_AIRGAP_URL}
125
125
  ></script>`}
126
126
  ${scripts?.map(
127
127
  (path) => html`<script src=${path} type="module"></script>`,
@@ -13,6 +13,9 @@ export class ServerComponent {
13
13
  /** @type {string | undefined} */
14
14
  static inlineScript;
15
15
 
16
+ /** `true` if we're rendering in a renderSimplified context */
17
+ simplifiedMode = false;
18
+
16
19
  /**
17
20
  * @template {typeof ServerComponent} T
18
21
  * @this {T}
@@ -28,6 +31,7 @@ export class ServerComponent {
28
31
  const component = new this();
29
32
 
30
33
  if ("renderSimplified" in asyncStore) {
34
+ component.simplifiedMode = true;
31
35
  return component.renderSimplified(...args);
32
36
  }
33
37
 
@@ -154,7 +154,9 @@ export class SidebarFilterer {
154
154
  * @param {HTMLAnchorElement} link The link element to reset.
155
155
  */
156
156
  resetHighlighting(link) {
157
- const nodes = [...link.querySelectorAll("span, mark")];
157
+ const nodes = [
158
+ ...link.querySelectorAll("span.sidebar-filter-mark-container, mark"),
159
+ ];
158
160
  const parents = new Set();
159
161
  for (const node of nodes) {
160
162
  const parent = node.parentElement;
@@ -250,7 +252,7 @@ export class SidebarFilterer {
250
252
  );
251
253
 
252
254
  const span = this.replaceChildNode(node, "span");
253
- span.className = "highlight-container";
255
+ span.className = "sidebar-filter-mark-container";
254
256
 
255
257
  /** @type {Text|undefined} */
256
258
  const initialRest = [...span.childNodes].find(
@@ -0,0 +1,72 @@
1
+ import { html } from "@lit-labs/ssr";
2
+ import { join } from "lit/directives/join.js";
3
+
4
+ import { ServerComponent } from "../server/index.js";
5
+
6
+ export class SpecificationsList extends ServerComponent {
7
+ /**
8
+ * @param {import("@fred").Context} context
9
+ * @param {import("@rari").Specification[]} specifications
10
+ */
11
+ render(context, specifications) {
12
+ if (specifications.length === 0) {
13
+ return html`${context.l10n(
14
+ "specifications-list-this-feature-does-not-appear-to",
15
+ )`This feature does not appear to be defined in any specification.`}`;
16
+ }
17
+
18
+ /** @type {Map<string, string[]>} */
19
+ const urlsByTitle = new Map();
20
+ for (const { title, bcdSpecificationURL: url } of specifications) {
21
+ const urls = urlsByTitle.get(title) ?? [];
22
+ urls.push(url);
23
+ urlsByTitle.set(title, urls);
24
+ }
25
+ const links = urlsByTitle
26
+ .entries()
27
+ .flatMap(([title, urls]) =>
28
+ urls.map((url) => this.renderLink(url, title)),
29
+ );
30
+
31
+ if (this.simplifiedMode) {
32
+ return html`<ul>
33
+ ${links.map((link) => html`<li>${link}</li>`)}
34
+ </ul>`;
35
+ }
36
+ return html`<table>
37
+ <thead>
38
+ <tr>
39
+ <th scope="col">
40
+ ${context.l10n("specifications-list-specification")`Specification`}
41
+ </th>
42
+ </tr>
43
+ </thead>
44
+ <tbody>
45
+ ${links.map(
46
+ (link) =>
47
+ html`<tr>
48
+ <td>${link}</td>
49
+ </tr>`,
50
+ )}
51
+ </tbody>
52
+ </table>`;
53
+ }
54
+
55
+ /**
56
+ * @param {string} url
57
+ * @param {string} [title]
58
+ */
59
+ renderLink(url, title) {
60
+ const hash = url.split("#")[1];
61
+
62
+ const label = [
63
+ title && html`${title}`,
64
+ title && hash && html`<br />`,
65
+ hash && html`# ${hash}`,
66
+ ].filter(Boolean);
67
+
68
+ return html`<a class="external" href=${url} rel="noopener" target="_blank"
69
+ >${join(label, "")}</a
70
+ >`;
71
+ }
72
+ }