@jsenv/core 39.11.2 → 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,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAJBlWElmTU0AKgAAAAgABgEGAAMAAAABAAIAAAESAAMAAAABAAEAAAEaAAUAAAABAAAAVgEbAAUAAAABAAAAXgEoAAMAAAABAAIAAIdpAAQAAAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAACCgAwAEAAAAAQAAACAAAAAAF9yy1AAAAAlwSFlzAAALEwAACxMBAJqcGAAAAgtpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpQaG90b21ldHJpY0ludGVycHJldGF0aW9uPjI8L3RpZmY6UGhvdG9tZXRyaWNJbnRlcnByZXRhdGlvbj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHRpZmY6Q29tcHJlc3Npb24+MTwvdGlmZjpDb21wcmVzc2lvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+Cu3MPn8AAAUrSURBVFgJzVdLi11FEK7u87pz7ziPmEViwGQhiLrKNuAqiKuYjf6G/AERBEHcuhHRlasgroWQ5BeIZDWgoi5EwUcSIczjZhzu49xzTvt9fao698ogiiNJzdSc032qq756dHWPyGMmd4x9f8ycTXX2clJPA0Cj5FIVHweCxhvlEwNCANHwGx9+/k515rm3fT70zjkJ0kYsRZ5JCEG6+ayTg3tfXL/26mv4MAETxH8GQgA5+NSV6zu/N+XQh85JR7WhB5AXmQCPuCBSZE5G47u/fnbt8kVIHIEZkX9LK6AJYAg+e+mTr3+cw/gCHtdtBxC9nM+deEj5Jsha7qUqM9moDw7d3R/e/W1n58Y3Nz/ew/oVpX+DyORqXQOLPYALz3/01XeTNsgs87KAWAMQJAcAkepOciAZAMB64WUIoBznRf/ZIHTQQeoyXS9ZHBdIao4wVmHeDR789P6tN19/Dx9qhp81kNONfUS9m8xFqGSBCVJBEVCjKalaeYhUsFoJwKlPrtK61cg534+7xSwuZx4dnPNZ7p8un30Lkx+A91W7yB48DKgzmcLQCgCNgAJoEB4mfqIRkka/D1YBiAKQRQ9cIJYhcq4sZLwGJCJPgY8SgHN5LlcunZPTm5WUCC/XsfhK1R9YCCCPUEZSz3UUMXPeAhbsO5ZhE0V9NZzYm87l9rf35Z5IRfkE4JWXzsqpzaGUVSYFQ4swkwoDoE/Fkcou2LwaPA5AVIQiliyTbeyqyy+ckU972z4BGI4qaaFsDsEOVgruO9BMDaRcx1l4pAbX+hqTucrVWjuMHklrUugPSz50QdYr63dLEWjgyhxKCTSyKuA7SfEwlZEMgA5FS+1RUargMoAG+uMOs7BhcYpAjdxmSBabAnM2V8O2GXL12HZl3MCQPdIaS8gUkVd5Sxn1teyokNeNEiW1dHXVY3ikCGRAloMXyCnSlNoAI0JCd4hkuaUnJA2UVKqp1uYc1LWJyo0gy507hRwjbPTkRKADlBYcc4wC0uK2DiuxdQC21URywopNPbW+YUU50O8cc5cJC3CpCJ+cCPD0JaNPxD27UBe9Pm3bqUNRhnm0cTxRMNaOnfJsHbmEHgZphqrhj1EqQm6XFVYJ20b2NIN/HVtxWnQttCZHk/zGeZujiQQgQ/LJrANKOa3m1Ei0KGyBRURTnxqQ1Qo9Jlm/YEQpG/uAFRLGpg+tl+0X57tGwjwxj21sC2ys/SalQo+QNLaX6D2U8brXLIXA9MULSAN3SwjQ2UZjaB4lj3WetUJieyXhpI3Edh5JkafDDJPsLz2ll0cR2D04kApah1mBQwsodQMWWkVmyBkwda3RvsoTlFTHvYZ895Yk1x7OBtXCwRY5mNkdATIpAqONDdz3MIQCD7eHasiquNBkO/XcdsnQPNbY267xdnrp9wyImhZKACK3drkMYH/3Ae4CpXQ4/jJYxf0zEsGQgobA6YdGbxxZrFoIqCsWZl2eLrcMVMs/+F3UvJP2ZBHAPQvQRkOX40KCfwzETrNWLwJek9lqqCv1bGEWVaEZdhoBq4EOVcjTtp63EiZTZihqIAC+TPe+vHVj++WrV/1oA+YBANHCCzLSWyIoEi8rJLsnEHckfagY1vYTTCEPnwAAbECLh4dh/87tm1jD8y3uUl5PtsDnwc9sXXjx/PrW6W2895bw8o/IYqn945g14Wi8ezD++ftf8O0+mM8xjTBqA/A6eBO8BmapWTTxeiLEULKUp+BD8B9gu/FFY/TBGK//CwDqZYyMuz8BNOHwEmx83xgAAAAASUVORK5CYII=);
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;
@@ -19399,6 +19399,7 @@ const jsenvPluginProtocolFile = ({
19399
19399
  return null;
19400
19400
  }
19401
19401
  const { firstReference } = urlInfo;
19402
+ const { mainFilePath } = urlInfo.context;
19402
19403
  let { fsStat } = firstReference;
19403
19404
  if (!fsStat) {
19404
19405
  fsStat = readEntryStatSync(urlInfo.url, { nullIfNotFound: true });
@@ -19428,6 +19429,7 @@ const jsenvPluginProtocolFile = ({
19428
19429
  urlInfo.url,
19429
19430
  directoryContentItems,
19430
19431
  directoryListingUrlMocks,
19432
+ { mainFilePath },
19431
19433
  );
19432
19434
  return {
19433
19435
  status: 404,
@@ -19459,7 +19461,9 @@ const jsenvPluginProtocolFile = ({
19459
19461
  directoryUrl,
19460
19462
  rootDirectoryUrl,
19461
19463
  );
19462
- const html = generateHtmlForDirectory(directoryContentItems);
19464
+ const html = generateHtmlForDirectory(directoryContentItems, {
19465
+ mainFilePath,
19466
+ });
19463
19467
  return {
19464
19468
  type: "html",
19465
19469
  contentType: "text/html",
@@ -19478,7 +19482,7 @@ const jsenvPluginProtocolFile = ({
19478
19482
  ];
19479
19483
  };
19480
19484
 
19481
- const generateHtmlForDirectory = (directoryContentItems) => {
19485
+ const generateHtmlForDirectory = (directoryContentItems, { mainFilePath }) => {
19482
19486
  let directoryUrl = directoryContentItems.firstExistingDirectoryUrl;
19483
19487
  const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
19484
19488
  directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
@@ -19491,8 +19495,10 @@ const generateHtmlForDirectory = (directoryContentItems) => {
19491
19495
  rootDirectoryUrl,
19492
19496
  rootDirectoryUrlForServer:
19493
19497
  directoryContentItems.rootDirectoryUrlForServer,
19498
+ mainFilePath,
19494
19499
  }),
19495
- directoryContent: () => generateDirectoryContent(directoryContentItems),
19500
+ directoryContent: () =>
19501
+ generateDirectoryContent(directoryContentItems, { mainFilePath }),
19496
19502
  };
19497
19503
  const html = replacePlaceholders$1(htmlForDirectory, replacers);
19498
19504
  return html;
@@ -19501,6 +19507,7 @@ const generateHtmlForENOENT = (
19501
19507
  url,
19502
19508
  directoryContentItems,
19503
19509
  directoryListingUrlMocks,
19510
+ { mainFilePath },
19504
19511
  ) => {
19505
19512
  const ancestorDirectoryUrl = directoryContentItems.firstExistingDirectoryUrl;
19506
19513
  const rootDirectoryUrl = directoryContentItems.rootDirectoryUrl;
@@ -19525,16 +19532,17 @@ const generateHtmlForENOENT = (
19525
19532
  rootDirectoryUrl,
19526
19533
  rootDirectoryUrlForServer:
19527
19534
  directoryContentItems.rootDirectoryUrlForServer,
19535
+ mainFilePath,
19528
19536
  }),
19529
19537
  ancestorDirectoryContent: () =>
19530
- generateDirectoryContent(directoryContentItems),
19538
+ generateDirectoryContent(directoryContentItems, { mainFilePath }),
19531
19539
  };
19532
19540
  const html = replacePlaceholders$1(htmlFor404AndAncestorDir, replacers);
19533
19541
  return html;
19534
19542
  };
19535
19543
  const generateDirectoryNav = (
19536
19544
  entryDirectoryUrl,
19537
- { rootDirectoryUrl, rootDirectoryUrlForServer },
19545
+ { rootDirectoryUrl, rootDirectoryUrlForServer, mainFilePath },
19538
19546
  ) => {
19539
19547
  const entryDirectoryRelativeUrl = urlToRelativeUrl(
19540
19548
  entryDirectoryUrl,
@@ -19576,19 +19584,45 @@ const generateDirectoryNav = (
19576
19584
  i++;
19577
19585
  }
19578
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
+
19579
19616
  for (const { href, text } of items) {
19580
19617
  const isLastPart = i === items.length - 1;
19618
+ dirPartsHtml += renderDirNavItem({
19619
+ isCurrent: isLastPart,
19620
+ href,
19621
+ text,
19622
+ });
19581
19623
  if (isLastPart) {
19582
- dirPartsHtml += `
19583
- <span class="directory_nav_item" data-current>
19584
- ${text}
19585
- </span>`;
19586
19624
  break;
19587
19625
  }
19588
- dirPartsHtml += `
19589
- <a class="directory_nav_item" href="${href}">
19590
- ${text}
19591
- </a>`;
19592
19626
  dirPartsHtml += `
19593
19627
  <span class="directory_separator">/</span>`;
19594
19628
  i++;
@@ -19692,7 +19726,7 @@ const generateDirectoryContentItems = (
19692
19726
  items.firstExistingDirectoryUrl = firstExistingDirectoryUrl;
19693
19727
  return items;
19694
19728
  };
19695
- const generateDirectoryContent = (directoryContentItems) => {
19729
+ const generateDirectoryContent = (directoryContentItems, { mainFilePath }) => {
19696
19730
  if (directoryContentItems.length === 0) {
19697
19731
  return `<p class="directory_empty_message">Directory is empty</p>`;
19698
19732
  }
@@ -19704,9 +19738,11 @@ const generateDirectoryContent = (directoryContentItems) => {
19704
19738
  if (href === "") {
19705
19739
  href = `${directoryContentMagicName}`;
19706
19740
  }
19741
+ const isMainFile = href === mainFilePath;
19742
+ const mainFileAttr = isMainFile ? ` data-main-file` : "";
19707
19743
  html += `
19708
- <li class="directory_child" data-type="${type}">
19709
- <a href="/${href}">${fileUrlRelativeToParent}</a>
19744
+ <li class="directory_child" data-type="${type}"${mainFileAttr}>
19745
+ <a href="/${href}" hot-decline>${fileUrlRelativeToParent}</a>
19710
19746
  </li>`;
19711
19747
  }
19712
19748
  html += `\n </ul>`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "39.11.2",
3
+ "version": "39.12.0",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -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>`;