@jsenv/core 39.11.1 → 39.12.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.
@@ -23,10 +23,24 @@
23
23
  }
24
24
 
25
25
  .directory_nav_item {
26
+ align-items: center;
27
+ display: flex;
28
+ }
29
+
30
+ .directory_nav_item a {
31
+ color: inherit;
26
32
  text-decoration: none;
27
33
  position: relative;
28
34
  }
29
35
 
36
+ .directory_root_for_server {
37
+ width: 1em;
38
+ height: 1em;
39
+ margin-right: .25em;
40
+ text-decoration: none;
41
+ display: flex;
42
+ }
43
+
30
44
  .directory_empty_message {
31
45
  color: #bbb;
32
46
  margin: 1em;
@@ -77,6 +91,11 @@
77
91
  background-image: url(data:image/png;base64,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);
78
92
  }
79
93
 
94
+ .directory_child[data-main-file], .directory_root_for_server {
95
+ background-image: url(data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAxMDAgMTAwOyIgZmlsbD0iI2YxZjFmMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIzMC40IDIzLjQ3IDQwLjA1IDQ1LjYzIj4KICAgIDxwYXRoIGQ9Ik0zMi41LDY5LjFjLTAuNiwwLTEuMS0wLjItMS40LTAuNWMtMC43LTAuNi0wLjctMS41LTAuNy0xLjhWNDEuMWg0djI0aDl2NEgzMi45QzMyLjgsNjkuMSwzMi42LDY5LjEsMzIuNSw2OS4xeiIvPgogICAgPHBhdGggZD0iTTY3LjgsNjkuMWMtMC4yLDAtMC4zLDAtMC41LDBjLTAuMSwwLTAuMSwwLTAuMiwwSDU2LjR2LTRoMTB2LTIzaDR2MjQuN2MwLDAuNi0wLjMsMS4yLTAuNywxLjcgIEM2OS4xLDY5LDY4LjMsNjkuMSw2Ny44LDY5LjF6Ii8+CiAgICA8cGF0aCAgZD0iTTY4LjQsNDQuMWMtMC41LDAtMS0wLjItMS4zLTAuNUw1MCwyOC4yTDMzLjcsNDIuNmMtMC44LDAuNy0yLjEsMC43LTIuOC0wLjJjLTAuNy0wLjgtMC43LTIuMSwwLjItMi44TDQ4LjcsMjQgIGMwLjgtMC43LDEuOS0wLjcsMi43LDBsMTguNCwxNi42YzAuOCwwLjcsMC45LDIsMC4xLDIuOEM2OS41LDQzLjgsNjguOSw0NC4xLDY4LjQsNDQuMXoiLz4KICAgIDxwYXRoICBkPSJNNTguNCw2OS4xaC00di0xM2gtOHYxM2gtNHYtMTVjMC0xLjEsMC45LTIsMi0yaDEyYzEuMSwwLDIsMC45LDIsMlY2OS4xeiIvPgo8L3N2Zz4=);
96
+ background-repeat: no-repeat;
97
+ }
98
+
80
99
  .directory_child[data-type="dir"]:before {
81
100
  content: " ";
82
101
  border-top-right-radius: 1px;
@@ -23,10 +23,24 @@
23
23
  }
24
24
 
25
25
  .directory_nav_item {
26
+ align-items: center;
27
+ display: flex;
28
+ }
29
+
30
+ .directory_nav_item a {
31
+ color: inherit;
26
32
  text-decoration: none;
27
33
  position: relative;
28
34
  }
29
35
 
36
+ .directory_root_for_server {
37
+ width: 1em;
38
+ height: 1em;
39
+ margin-right: .25em;
40
+ text-decoration: none;
41
+ display: flex;
42
+ }
43
+
30
44
  .directory_empty_message {
31
45
  color: #bbb;
32
46
  margin: 1em;
@@ -77,6 +91,11 @@
77
91
  background-image: url(data:image/png;base64,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);
78
92
  }
79
93
 
94
+ .directory_child[data-main-file], .directory_root_for_server {
95
+ background-image: url(data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAxMDAgMTAwOyIgZmlsbD0iI2YxZjFmMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIzMC40IDIzLjQ3IDQwLjA1IDQ1LjYzIj4KICAgIDxwYXRoIGQ9Ik0zMi41LDY5LjFjLTAuNiwwLTEuMS0wLjItMS40LTAuNWMtMC43LTAuNi0wLjctMS41LTAuNy0xLjhWNDEuMWg0djI0aDl2NEgzMi45QzMyLjgsNjkuMSwzMi42LDY5LjEsMzIuNSw2OS4xeiIvPgogICAgPHBhdGggZD0iTTY3LjgsNjkuMWMtMC4yLDAtMC4zLDAtMC41LDBjLTAuMSwwLTAuMSwwLTAuMiwwSDU2LjR2LTRoMTB2LTIzaDR2MjQuN2MwLDAuNi0wLjMsMS4yLTAuNywxLjcgIEM2OS4xLDY5LDY4LjMsNjkuMSw2Ny44LDY5LjF6Ii8+CiAgICA8cGF0aCAgZD0iTTY4LjQsNDQuMWMtMC41LDAtMS0wLjItMS4zLTAuNUw1MCwyOC4yTDMzLjcsNDIuNmMtMC44LDAuNy0yLjEsMC43LTIuOC0wLjJjLTAuNy0wLjgtMC43LTIuMSwwLjItMi44TDQ4LjcsMjQgIGMwLjgtMC43LDEuOS0wLjcsMi43LDBsMTguNCwxNi42YzAuOCwwLjcsMC45LDIsMC4xLDIuOEM2OS41LDQzLjgsNjguOSw0NC4xLDY4LjQsNDQuMXoiLz4KICAgIDxwYXRoICBkPSJNNTguNCw2OS4xaC00di0xM2gtOHYxM2gtNHYtMTVjMC0xLjEsMC45LTIsMi0yaDEyYzEuMSwwLDIsMC45LDIsMlY2OS4xeiIvPgo8L3N2Zz4=);
96
+ background-repeat: no-repeat;
97
+ }
98
+
80
99
  .directory_child[data-type="dir"]:before {
81
100
  content: " ";
82
101
  border-top-right-radius: 1px;
@@ -8399,6 +8399,10 @@ const getMtimeResponse = async ({ headers, fileStat }) => {
8399
8399
  };
8400
8400
 
8401
8401
  const getCompressedResponse = async ({ fileUrl, headers }) => {
8402
+ const contentType = CONTENT_TYPE.fromUrlExtension(fileUrl);
8403
+ if (CONTENT_TYPE.isBinary(contentType)) {
8404
+ return null;
8405
+ }
8402
8406
  const acceptedCompressionFormat = pickContentEncoding(
8403
8407
  { headers },
8404
8408
  Object.keys(availableCompressionFormats),
@@ -8416,7 +8420,7 @@ const getCompressedResponse = async ({ fileUrl, headers }) => {
8416
8420
  return {
8417
8421
  status: 200,
8418
8422
  headers: {
8419
- "content-type": CONTENT_TYPE.fromUrlExtension(fileUrl),
8423
+ "content-type": contentType,
8420
8424
  "content-encoding": acceptedCompressionFormat,
8421
8425
  "vary": "accept-encoding",
8422
8426
  },
@@ -19395,6 +19399,7 @@ const jsenvPluginProtocolFile = ({
19395
19399
  return null;
19396
19400
  }
19397
19401
  const { firstReference } = urlInfo;
19402
+ const { mainFilePath } = urlInfo.context;
19398
19403
  let { fsStat } = firstReference;
19399
19404
  if (!fsStat) {
19400
19405
  fsStat = readEntryStatSync(urlInfo.url, { nullIfNotFound: true });
@@ -19424,6 +19429,7 @@ const jsenvPluginProtocolFile = ({
19424
19429
  urlInfo.url,
19425
19430
  directoryContentItems,
19426
19431
  directoryListingUrlMocks,
19432
+ { mainFilePath },
19427
19433
  );
19428
19434
  return {
19429
19435
  status: 404,
@@ -19455,7 +19461,9 @@ const jsenvPluginProtocolFile = ({
19455
19461
  directoryUrl,
19456
19462
  rootDirectoryUrl,
19457
19463
  );
19458
- const html = generateHtmlForDirectory(directoryContentItems);
19464
+ const html = generateHtmlForDirectory(directoryContentItems, {
19465
+ mainFilePath,
19466
+ });
19459
19467
  return {
19460
19468
  type: "html",
19461
19469
  contentType: "text/html",
@@ -19474,7 +19482,7 @@ const jsenvPluginProtocolFile = ({
19474
19482
  ];
19475
19483
  };
19476
19484
 
19477
- const generateHtmlForDirectory = (directoryContentItems) => {
19485
+ const generateHtmlForDirectory = (directoryContentItems, { mainFilePath }) => {
19478
19486
  let directoryUrl = directoryContentItems.firstExistingDirectoryUrl;
19479
19487
  const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
19480
19488
  directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
@@ -19487,8 +19495,10 @@ const generateHtmlForDirectory = (directoryContentItems) => {
19487
19495
  rootDirectoryUrl,
19488
19496
  rootDirectoryUrlForServer:
19489
19497
  directoryContentItems.rootDirectoryUrlForServer,
19498
+ mainFilePath,
19490
19499
  }),
19491
- directoryContent: () => generateDirectoryContent(directoryContentItems),
19500
+ directoryContent: () =>
19501
+ generateDirectoryContent(directoryContentItems, { mainFilePath }),
19492
19502
  };
19493
19503
  const html = replacePlaceholders$1(htmlForDirectory, replacers);
19494
19504
  return html;
@@ -19497,6 +19507,7 @@ const generateHtmlForENOENT = (
19497
19507
  url,
19498
19508
  directoryContentItems,
19499
19509
  directoryListingUrlMocks,
19510
+ { mainFilePath },
19500
19511
  ) => {
19501
19512
  const ancestorDirectoryUrl = directoryContentItems.firstExistingDirectoryUrl;
19502
19513
  const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
@@ -19521,16 +19532,17 @@ const generateHtmlForENOENT = (
19521
19532
  rootDirectoryUrl,
19522
19533
  rootDirectoryUrlForServer:
19523
19534
  directoryContentItems.rootDirectoryUrlForServer,
19535
+ mainFilePath,
19524
19536
  }),
19525
19537
  ancestorDirectoryContent: () =>
19526
- generateDirectoryContent(directoryContentItems),
19538
+ generateDirectoryContent(directoryContentItems, { mainFilePath }),
19527
19539
  };
19528
19540
  const html = replacePlaceholders$1(htmlFor404AndAncestorDir, replacers);
19529
19541
  return html;
19530
19542
  };
19531
19543
  const generateDirectoryNav = (
19532
19544
  entryDirectoryUrl,
19533
- { rootDirectoryUrl, rootDirectoryUrlForServer },
19545
+ { rootDirectoryUrl, rootDirectoryUrlForServer, mainFilePath },
19534
19546
  ) => {
19535
19547
  const entryDirectoryRelativeUrl = urlToRelativeUrl(
19536
19548
  entryDirectoryUrl,
@@ -19572,19 +19584,45 @@ const generateDirectoryNav = (
19572
19584
  i++;
19573
19585
  }
19574
19586
  i = 0;
19587
+
19588
+ const renderDirNavItem = ({ isCurrent, href, text }) => {
19589
+ const isServerRootDir = href === `/${directoryContentMagicName}`;
19590
+ if (isServerRootDir) {
19591
+ if (isCurrent) {
19592
+ return `
19593
+ <span class="directory_nav_item" data-current>
19594
+ <a class="directory_root_for_server" hot-decline href="/${mainFilePath}"></a>
19595
+ <span class="directory_name">${text}</span>
19596
+ </span>`;
19597
+ }
19598
+ return `
19599
+ <span class="directory_nav_item">
19600
+ <a class="directory_root_for_server" hot-decline href="/${mainFilePath}"></a>
19601
+ <a class="directory_name" hot-decline href="${href}">${text}</a>
19602
+ </span>`;
19603
+ }
19604
+ if (isCurrent) {
19605
+ return `
19606
+ <span class="directory_nav_item" data-current>
19607
+ <span class="directory_text">${text}</span>
19608
+ </span>`;
19609
+ }
19610
+ return `
19611
+ <span class="directory_nav_item">
19612
+ <a class="directory_text" hot-decline href="${href}">${text}</a>
19613
+ </span>`;
19614
+ };
19615
+
19575
19616
  for (const { href, text } of items) {
19576
19617
  const isLastPart = i === items.length - 1;
19618
+ dirPartsHtml += renderDirNavItem({
19619
+ isCurrent: isLastPart,
19620
+ href,
19621
+ text,
19622
+ });
19577
19623
  if (isLastPart) {
19578
- dirPartsHtml += `
19579
- <span class="directory_nav_item" data-current>
19580
- ${text}
19581
- </span>`;
19582
19624
  break;
19583
19625
  }
19584
- dirPartsHtml += `
19585
- <a class="directory_nav_item" href="${href}">
19586
- ${text}
19587
- </a>`;
19588
19626
  dirPartsHtml += `
19589
19627
  <span class="directory_separator">/</span>`;
19590
19628
  i++;
@@ -19688,7 +19726,7 @@ const generateDirectoryContentItems = (
19688
19726
  items.firstExistingDirectoryUrl = firstExistingDirectoryUrl;
19689
19727
  return items;
19690
19728
  };
19691
- const generateDirectoryContent = (directoryContentItems) => {
19729
+ const generateDirectoryContent = (directoryContentItems, { mainFilePath }) => {
19692
19730
  if (directoryContentItems.length === 0) {
19693
19731
  return `<p class="directory_empty_message">Directory is empty</p>`;
19694
19732
  }
@@ -19700,9 +19738,11 @@ const generateDirectoryContent = (directoryContentItems) => {
19700
19738
  if (href === "") {
19701
19739
  href = `${directoryContentMagicName}`;
19702
19740
  }
19741
+ const isMainFile = href === mainFilePath;
19742
+ const mainFileAttr = isMainFile ? ` data-main-file` : "";
19703
19743
  html += `
19704
- <li class="directory_child" data-type="${type}">
19705
- <a href="/${href}">${fileUrlRelativeToParent}</a>
19744
+ <li class="directory_child" data-type="${type}"${mainFileAttr}>
19745
+ <a href="/${href}" hot-decline>${fileUrlRelativeToParent}</a>
19706
19746
  </li>`;
19707
19747
  }
19708
19748
  html += `\n </ul>`;
@@ -24609,7 +24649,7 @@ const createBuildFilesService = ({ buildDirectoryUrl, buildMainFilePath }) => {
24609
24649
  ? `private,max-age=${SECONDS_IN_30_DAYS},immutable`
24610
24650
  : "private,max-age=0,must-revalidate",
24611
24651
  etagEnabled: true,
24612
- compressionEnabled: !request.pathname.endsWith(".mp4"),
24652
+ compressionEnabled: true,
24613
24653
  rootDirectoryUrl: buildDirectoryUrl,
24614
24654
  canReadDirectory: true,
24615
24655
  ENOENTFallback: () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "39.11.1",
3
+ "version": "39.12.0",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -81,7 +81,7 @@
81
81
  "@jsenv/plugin-supervisor": "1.6.3",
82
82
  "@jsenv/plugin-transpilation": "1.4.92",
83
83
  "@jsenv/runtime-compat": "1.3.1",
84
- "@jsenv/server": "15.4.0",
84
+ "@jsenv/server": "15.4.1",
85
85
  "@jsenv/sourcemap": "1.2.30",
86
86
  "@jsenv/url-meta": "8.5.2",
87
87
  "@jsenv/urls": "2.6.0",
@@ -176,7 +176,7 @@ const createBuildFilesService = ({ buildDirectoryUrl, buildMainFilePath }) => {
176
176
  ? `private,max-age=${SECONDS_IN_30_DAYS},immutable`
177
177
  : "private,max-age=0,must-revalidate",
178
178
  etagEnabled: true,
179
- compressionEnabled: !request.pathname.endsWith(".mp4"),
179
+ compressionEnabled: true,
180
180
  rootDirectoryUrl: buildDirectoryUrl,
181
181
  canReadDirectory: true,
182
182
  ENOENTFallback: () => {
@@ -23,8 +23,20 @@ button {
23
23
  gap: 0.3em;
24
24
  }
25
25
  .directory_nav_item {
26
+ display: flex;
27
+ align-items: center;
28
+ }
29
+ .directory_nav_item a {
26
30
  text-decoration: none;
27
31
  position: relative;
32
+ color: inherit;
33
+ }
34
+ .directory_root_for_server {
35
+ text-decoration: none;
36
+ display: flex;
37
+ width: 1em;
38
+ height: 1em;
39
+ margin-right: 0.25em;
28
40
  }
29
41
  .directory_empty_message {
30
42
  margin: 1em;
@@ -68,6 +80,11 @@ button {
68
80
  .directory_child[data-type="dir"] {
69
81
  background-image: url("./dir.png?inline");
70
82
  }
83
+ .directory_child[data-main-file],
84
+ .directory_root_for_server {
85
+ background-image: url("./home.svg?inline");
86
+ background-repeat: no-repeat;
87
+ }
71
88
  .directory_child[data-type="dir"]::before {
72
89
  content: " ";
73
90
  position: absolute;
@@ -0,0 +1,6 @@
1
+ <svg style="enable-background:new 0 0 100 100;" fill="#f1f1f1" xmlns="http://www.w3.org/2000/svg" viewBox="30.4 23.47 40.05 45.63">
2
+ <path d="M32.5,69.1c-0.6,0-1.1-0.2-1.4-0.5c-0.7-0.6-0.7-1.5-0.7-1.8V41.1h4v24h9v4H32.9C32.8,69.1,32.6,69.1,32.5,69.1z"/>
3
+ <path d="M67.8,69.1c-0.2,0-0.3,0-0.5,0c-0.1,0-0.1,0-0.2,0H56.4v-4h10v-23h4v24.7c0,0.6-0.3,1.2-0.7,1.7 C69.1,69,68.3,69.1,67.8,69.1z"/>
4
+ <path d="M68.4,44.1c-0.5,0-1-0.2-1.3-0.5L50,28.2L33.7,42.6c-0.8,0.7-2.1,0.7-2.8-0.2c-0.7-0.8-0.7-2.1,0.2-2.8L48.7,24 c0.8-0.7,1.9-0.7,2.7,0l18.4,16.6c0.8,0.7,0.9,2,0.1,2.8C69.5,43.8,68.9,44.1,68.4,44.1z"/>
5
+ <path d="M58.4,69.1h-4v-13h-8v13h-4v-15c0-1.1,0.9-2,2-2h12c1.1,0,2,0.9,2,2V69.1z"/>
6
+ </svg>
@@ -97,6 +97,7 @@ export const jsenvPluginProtocolFile = ({
97
97
  return null;
98
98
  }
99
99
  const { firstReference } = urlInfo;
100
+ const { mainFilePath } = urlInfo.context;
100
101
  let { fsStat } = firstReference;
101
102
  if (!fsStat) {
102
103
  fsStat = readEntryStatSync(urlInfo.url, { nullIfNotFound: true });
@@ -126,6 +127,7 @@ export const jsenvPluginProtocolFile = ({
126
127
  urlInfo.url,
127
128
  directoryContentItems,
128
129
  directoryListingUrlMocks,
130
+ { mainFilePath },
129
131
  );
130
132
  return {
131
133
  status: 404,
@@ -157,7 +159,9 @@ export const jsenvPluginProtocolFile = ({
157
159
  directoryUrl,
158
160
  rootDirectoryUrl,
159
161
  );
160
- const html = generateHtmlForDirectory(directoryContentItems);
162
+ const html = generateHtmlForDirectory(directoryContentItems, {
163
+ mainFilePath,
164
+ });
161
165
  return {
162
166
  type: "html",
163
167
  contentType: "text/html",
@@ -176,7 +180,7 @@ export const jsenvPluginProtocolFile = ({
176
180
  ];
177
181
  };
178
182
 
179
- const generateHtmlForDirectory = (directoryContentItems) => {
183
+ const generateHtmlForDirectory = (directoryContentItems, { mainFilePath }) => {
180
184
  let directoryUrl = directoryContentItems.firstExistingDirectoryUrl;
181
185
  const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
182
186
  directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
@@ -189,8 +193,10 @@ const generateHtmlForDirectory = (directoryContentItems) => {
189
193
  rootDirectoryUrl,
190
194
  rootDirectoryUrlForServer:
191
195
  directoryContentItems.rootDirectoryUrlForServer,
196
+ mainFilePath,
192
197
  }),
193
- directoryContent: () => generateDirectoryContent(directoryContentItems),
198
+ directoryContent: () =>
199
+ generateDirectoryContent(directoryContentItems, { mainFilePath }),
194
200
  };
195
201
  const html = replacePlaceholders(htmlForDirectory, replacers);
196
202
  return html;
@@ -199,6 +205,7 @@ const generateHtmlForENOENT = (
199
205
  url,
200
206
  directoryContentItems,
201
207
  directoryListingUrlMocks,
208
+ { mainFilePath },
202
209
  ) => {
203
210
  const ancestorDirectoryUrl = directoryContentItems.firstExistingDirectoryUrl;
204
211
  const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
@@ -223,16 +230,17 @@ const generateHtmlForENOENT = (
223
230
  rootDirectoryUrl,
224
231
  rootDirectoryUrlForServer:
225
232
  directoryContentItems.rootDirectoryUrlForServer,
233
+ mainFilePath,
226
234
  }),
227
235
  ancestorDirectoryContent: () =>
228
- generateDirectoryContent(directoryContentItems),
236
+ generateDirectoryContent(directoryContentItems, { mainFilePath }),
229
237
  };
230
238
  const html = replacePlaceholders(htmlFor404AndAncestorDir, replacers);
231
239
  return html;
232
240
  };
233
241
  const generateDirectoryNav = (
234
242
  entryDirectoryUrl,
235
- { rootDirectoryUrl, rootDirectoryUrlForServer },
243
+ { rootDirectoryUrl, rootDirectoryUrlForServer, mainFilePath },
236
244
  ) => {
237
245
  const entryDirectoryRelativeUrl = urlToRelativeUrl(
238
246
  entryDirectoryUrl,
@@ -274,19 +282,45 @@ const generateDirectoryNav = (
274
282
  i++;
275
283
  }
276
284
  i = 0;
285
+
286
+ const renderDirNavItem = ({ isCurrent, href, text }) => {
287
+ const isServerRootDir = href === `/${directoryContentMagicName}`;
288
+ if (isServerRootDir) {
289
+ if (isCurrent) {
290
+ return `
291
+ <span class="directory_nav_item" data-current>
292
+ <a class="directory_root_for_server" hot-decline href="/${mainFilePath}"></a>
293
+ <span class="directory_name">${text}</span>
294
+ </span>`;
295
+ }
296
+ return `
297
+ <span class="directory_nav_item">
298
+ <a class="directory_root_for_server" hot-decline href="/${mainFilePath}"></a>
299
+ <a class="directory_name" hot-decline href="${href}">${text}</a>
300
+ </span>`;
301
+ }
302
+ if (isCurrent) {
303
+ return `
304
+ <span class="directory_nav_item" data-current>
305
+ <span class="directory_text">${text}</span>
306
+ </span>`;
307
+ }
308
+ return `
309
+ <span class="directory_nav_item">
310
+ <a class="directory_text" hot-decline href="${href}">${text}</a>
311
+ </span>`;
312
+ };
313
+
277
314
  for (const { href, text } of items) {
278
315
  const isLastPart = i === items.length - 1;
316
+ dirPartsHtml += renderDirNavItem({
317
+ isCurrent: isLastPart,
318
+ href,
319
+ text,
320
+ });
279
321
  if (isLastPart) {
280
- dirPartsHtml += `
281
- <span class="directory_nav_item" data-current>
282
- ${text}
283
- </span>`;
284
322
  break;
285
323
  }
286
- dirPartsHtml += `
287
- <a class="directory_nav_item" href="${href}">
288
- ${text}
289
- </a>`;
290
324
  dirPartsHtml += `
291
325
  <span class="directory_separator">/</span>`;
292
326
  i++;
@@ -390,7 +424,7 @@ const generateDirectoryContentItems = (
390
424
  items.firstExistingDirectoryUrl = firstExistingDirectoryUrl;
391
425
  return items;
392
426
  };
393
- const generateDirectoryContent = (directoryContentItems) => {
427
+ const generateDirectoryContent = (directoryContentItems, { mainFilePath }) => {
394
428
  if (directoryContentItems.length === 0) {
395
429
  return `<p class="directory_empty_message">Directory is empty</p>`;
396
430
  }
@@ -402,9 +436,11 @@ const generateDirectoryContent = (directoryContentItems) => {
402
436
  if (href === "") {
403
437
  href = `${directoryContentMagicName}`;
404
438
  }
439
+ const isMainFile = href === mainFilePath;
440
+ const mainFileAttr = isMainFile ? ` data-main-file` : "";
405
441
  html += `
406
- <li class="directory_child" data-type="${type}">
407
- <a href="/${href}">${fileUrlRelativeToParent}</a>
442
+ <li class="directory_child" data-type="${type}"${mainFileAttr}>
443
+ <a href="/${href}" hot-decline>${fileUrlRelativeToParent}</a>
408
444
  </li>`;
409
445
  }
410
446
  html += `\n </ul>`;