]> Untitled Git - lemmy-ui.git/commitdiff
Navbar hide menu fix (#1033)
authorSleeplessOne1917 <abias1122@gmail.com>
Mon, 22 May 2023 03:31:08 +0000 (03:31 +0000)
committerGitHub <noreply@github.com>
Mon, 22 May 2023 03:31:08 +0000 (23:31 -0400)
* Fix navbar not closing on mobile when it should

* Get rid of unnecessary HTML tags

package.json
src/assets/css/main.css
src/client/index.tsx
src/shared/components/app/navbar.tsx
yarn.lock

index 2f16b8d3797fc72970f25074a864492d7645fc61..641a87aa7e03d4bf03511e6f4ef5f3a92db6c0d8 100644 (file)
@@ -89,6 +89,7 @@
   "devDependencies": {
     "@babel/core": "^7.21.8",
     "@types/autosize": "^4.0.0",
+    "@types/bootstrap": "^5.2.6",
     "@types/express": "^4.17.17",
     "@types/html-to-text": "^9.0.0",
     "@types/markdown-it": "^12.2.3",
index 9cff2c7f5eb0286ca653194af8fbef49c929091a..a0d723940c9d0a136e40aa26df49676bd86f4343 100644 (file)
@@ -1,7 +1,3 @@
-.navbar-toggler {
-  border: 0px;
-}
-
 .navbar-expand-lg .navbar-nav .nav-link {
   padding-right: 0.75rem !important;
   padding-left: 0.75rem !important;
   }
 }
 
-.dropdown-content {
-  position: absolute;
-  background-color: var(--light);
-  min-width: 160px;
-  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
-  z-index: 2000;
-}
-
 blockquote {
   border-left: 2px solid var(--secondary);
   margin: 0.5em 5px;
index d3a5b625b1212fc44bf4343eee42ef6f596da2f0..99f12371a10a4205f1ec95084d969619b013e2eb 100644 (file)
@@ -3,6 +3,7 @@ import { BrowserRouter } from "inferno-router";
 import { App } from "../shared/components/app/app";
 import { initializeSite } from "../shared/utils";
 
+import "bootstrap/js/dist/collapse";
 import "bootstrap/js/dist/dropdown";
 
 const site = window.isoData.site_res;
index 128d40238cebd9695004476939660b4904692859..f9497c7b09c2d6dc1ad216c9912483132cf6cc10 100644 (file)
@@ -1,4 +1,4 @@
-import { Component, linkEvent } from "inferno";
+import { Component, createRef, linkEvent } from "inferno";
 import { NavLink } from "inferno-router";
 import {
   CommentResponse,
@@ -39,14 +39,22 @@ interface NavbarProps {
 }
 
 interface NavbarState {
-  expanded: boolean;
   unreadInboxCount: number;
   unreadReportCount: number;
   unreadApplicationCount: number;
-  showDropdown: boolean;
   onSiteBanner?(url: string): any;
 }
 
+function handleCollapseClick(i: Navbar) {
+  if (i.collapseButtonRef.current?.ariaExpanded === "true") {
+    i.collapseButtonRef.current?.click();
+  }
+}
+
+function handleLogOut() {
+  UserService.Instance.logout();
+}
+
 export class Navbar extends Component<NavbarProps, NavbarState> {
   private wsSub: Subscription;
   private userSub: Subscription;
@@ -57,10 +65,9 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
     unreadInboxCount: 0,
     unreadReportCount: 0,
     unreadApplicationCount: 0,
-    expanded: false,
-    showDropdown: false,
   };
   subscription: any;
+  collapseButtonRef = createRef<HTMLButtonElement>();
 
   constructor(props: any, context: any) {
     super(props, context);
@@ -113,85 +120,228 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
     this.unreadApplicationCountSub.unsubscribe();
   }
 
-  render() {
-    return this.navbar();
-  }
-
   // TODO class active corresponding to current page
-  navbar() {
-    let siteView = this.props.siteRes.site_view;
-    let person = UserService.Instance.myUserInfo?.local_user_view.person;
+  render() {
+    const siteView = this.props.siteRes.site_view;
+    const person = UserService.Instance.myUserInfo?.local_user_view.person;
     return (
-      <nav className="navbar navbar-expand-md navbar-light shadow-sm p-0 px-3">
-        <div className="container-lg">
-          <NavLink
-            to="/"
-            onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
-            title={siteView.site.description ?? siteView.site.name}
-            className="d-flex align-items-center navbar-brand mr-md-3"
-          >
-            {siteView.site.icon && showAvatars() && (
-              <PictrsImage src={siteView.site.icon} icon />
+      <nav className="navbar navbar-expand-md navbar-light shadow-sm p-0 px-3 container-lg">
+        <NavLink
+          to="/"
+          title={siteView.site.description ?? siteView.site.name}
+          className="d-flex align-items-center navbar-brand mr-md-3"
+          onMouseUp={linkEvent(this, handleCollapseClick)}
+        >
+          {siteView.site.icon && showAvatars() && (
+            <PictrsImage src={siteView.site.icon} icon />
+          )}
+          {siteView.site.name}
+        </NavLink>
+        {person && (
+          <ul className="navbar-nav d-flex flex-row ml-auto d-md-none">
+            <li className="nav-item">
+              <NavLink
+                to="/inbox"
+                className="p-1 nav-link border-0"
+                title={i18n.t("unread_messages", {
+                  count: Number(this.state.unreadInboxCount),
+                  formattedCount: numToSI(this.state.unreadInboxCount),
+                })}
+                onMouseUp={linkEvent(this, handleCollapseClick)}
+              >
+                <Icon icon="bell" />
+                {this.state.unreadInboxCount > 0 && (
+                  <span className="mx-1 badge badge-light">
+                    {numToSI(this.state.unreadInboxCount)}
+                  </span>
+                )}
+              </NavLink>
+            </li>
+            {this.moderatesSomething && (
+              <li className="nav-item">
+                <NavLink
+                  to="/reports"
+                  className="p-1 nav-link border-0"
+                  title={i18n.t("unread_reports", {
+                    count: Number(this.state.unreadReportCount),
+                    formattedCount: numToSI(this.state.unreadReportCount),
+                  })}
+                  onMouseUp={linkEvent(this, handleCollapseClick)}
+                >
+                  <Icon icon="shield" />
+                  {this.state.unreadReportCount > 0 && (
+                    <span className="mx-1 badge badge-light">
+                      {numToSI(this.state.unreadReportCount)}
+                    </span>
+                  )}
+                </NavLink>
+              </li>
             )}
-            {siteView.site.name}
-          </NavLink>
-          {UserService.Instance.myUserInfo && (
-            <>
-              <ul className="navbar-nav ml-auto">
+            {amAdmin() && (
+              <li className="nav-item">
+                <NavLink
+                  to="/registration_applications"
+                  className="p-1 nav-link border-0"
+                  title={i18n.t("unread_registration_applications", {
+                    count: Number(this.state.unreadApplicationCount),
+                    formattedCount: numToSI(this.state.unreadApplicationCount),
+                  })}
+                  onMouseUp={linkEvent(this, handleCollapseClick)}
+                >
+                  <Icon icon="clipboard" />
+                  {this.state.unreadApplicationCount > 0 && (
+                    <span className="mx-1 badge badge-light">
+                      {numToSI(this.state.unreadApplicationCount)}
+                    </span>
+                  )}
+                </NavLink>
+              </li>
+            )}
+          </ul>
+        )}
+        <button
+          className="navbar-toggler border-0 p-1"
+          type="button"
+          aria-label="menu"
+          data-tippy-content={i18n.t("expand_here")}
+          data-bs-toggle="collapse"
+          data-bs-target="#navbarDropdown"
+          aria-controls="navbarDropdown"
+          aria-expanded="false"
+          ref={this.collapseButtonRef}
+        >
+          <Icon icon="menu" />
+        </button>
+        <div className="collapse navbar-collapse my-2" id="navbarDropdown">
+          <ul className="mr-auto navbar-nav">
+            <li className="nav-item">
+              <NavLink
+                to="/communities"
+                className="nav-link"
+                title={i18n.t("communities")}
+                onMouseUp={linkEvent(this, handleCollapseClick)}
+              >
+                {i18n.t("communities")}
+              </NavLink>
+            </li>
+            <li className="nav-item">
+              {/* TODO make sure this works: https://github.com/infernojs/inferno/issues/1608 */}
+              <NavLink
+                to={{
+                  pathname: "/create_post",
+                  search: "",
+                  hash: "",
+                  key: "",
+                  state: { prevPath: this.currentLocation },
+                }}
+                className="nav-link"
+                title={i18n.t("create_post")}
+                onMouseUp={linkEvent(this, handleCollapseClick)}
+              >
+                {i18n.t("create_post")}
+              </NavLink>
+            </li>
+            {canCreateCommunity(this.props.siteRes) && (
+              <li className="nav-item">
+                <NavLink
+                  to="/create_community"
+                  className="nav-link"
+                  title={i18n.t("create_community")}
+                  onMouseUp={linkEvent(this, handleCollapseClick)}
+                >
+                  {i18n.t("create_community")}
+                </NavLink>
+              </li>
+            )}
+            <li className="nav-item">
+              <a
+                className="nav-link"
+                title={i18n.t("support_lemmy")}
+                href={donateLemmyUrl}
+              >
+                <Icon icon="heart" classes="small" />
+              </a>
+            </li>
+          </ul>
+          <ul className="navbar-nav">
+            {!this.context.router.history.location.pathname.match(
+              /^\/search/
+            ) && (
+              <li className="nav-item">
+                <NavLink
+                  to="/search"
+                  className="nav-link"
+                  title={i18n.t("search")}
+                  onMouseUp={linkEvent(this, handleCollapseClick)}
+                >
+                  <Icon icon="search" />
+                </NavLink>
+              </li>
+            )}
+            {amAdmin() && (
+              <li className="nav-item">
+                <NavLink
+                  to="/admin"
+                  className="nav-link"
+                  title={i18n.t("admin_settings")}
+                  onMouseUp={linkEvent(this, handleCollapseClick)}
+                >
+                  <Icon icon="settings" />
+                </NavLink>
+              </li>
+            )}
+            {person ? (
+              <>
                 <li className="nav-item">
                   <NavLink
+                    className="nav-link"
                     to="/inbox"
-                    className="p-1 navbar-toggler nav-link border-0"
-                    onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
                     title={i18n.t("unread_messages", {
                       count: Number(this.state.unreadInboxCount),
                       formattedCount: numToSI(this.state.unreadInboxCount),
                     })}
+                    onMouseUp={linkEvent(this, handleCollapseClick)}
                   >
                     <Icon icon="bell" />
                     {this.state.unreadInboxCount > 0 && (
-                      <span className="mx-1 badge badge-light">
+                      <span className="ml-1 badge badge-light">
                         {numToSI(this.state.unreadInboxCount)}
                       </span>
                     )}
                   </NavLink>
                 </li>
-              </ul>
-              {this.moderatesSomething && (
-                <ul className="navbar-nav ml-1">
+                {this.moderatesSomething && (
                   <li className="nav-item">
                     <NavLink
+                      className="nav-link"
                       to="/reports"
-                      className="p-1 navbar-toggler nav-link border-0"
-                      onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
                       title={i18n.t("unread_reports", {
                         count: Number(this.state.unreadReportCount),
                         formattedCount: numToSI(this.state.unreadReportCount),
                       })}
+                      onMouseUp={linkEvent(this, handleCollapseClick)}
                     >
                       <Icon icon="shield" />
                       {this.state.unreadReportCount > 0 && (
-                        <span className="mx-1 badge badge-light">
+                        <span className="ml-1 badge badge-light">
                           {numToSI(this.state.unreadReportCount)}
                         </span>
                       )}
                     </NavLink>
                   </li>
-                </ul>
-              )}
-              {amAdmin() && (
-                <ul className="navbar-nav ml-1">
+                )}
+                {amAdmin() && (
                   <li className="nav-item">
                     <NavLink
                       to="/registration_applications"
-                      className="p-1 navbar-toggler nav-link border-0"
-                      onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
+                      className="nav-link"
                       title={i18n.t("unread_registration_applications", {
                         count: Number(this.state.unreadApplicationCount),
                         formattedCount: numToSI(
                           this.state.unreadApplicationCount
                         ),
                       })}
+                      onMouseUp={linkEvent(this, handleCollapseClick)}
                     >
                       <Icon icon="clipboard" />
                       {this.state.unreadApplicationCount > 0 && (
@@ -201,241 +351,70 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
                       )}
                     </NavLink>
                   </li>
-                </ul>
-              )}
-            </>
-          )}
-          <button
-            className="navbar-toggler border-0 p-1"
-            type="button"
-            aria-label="menu"
-            onClick={linkEvent(this, this.handleToggleExpandNavbar)}
-            data-tippy-content={i18n.t("expand_here")}
-          >
-            <Icon icon="menu" />
-          </button>
-          <div
-            className={`${!this.state.expanded && "collapse"} navbar-collapse`}
-          >
-            <ul className="navbar-nav my-2 mr-auto">
-              <li className="nav-item">
-                <NavLink
-                  to="/communities"
-                  className="nav-link"
-                  onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
-                  title={i18n.t("communities")}
-                >
-                  {i18n.t("communities")}
-                </NavLink>
-              </li>
-              <li className="nav-item">
-                {/* TODO make sure this works: https://github.com/infernojs/inferno/issues/1608 */}
-                <NavLink
-                  to={{
-                    pathname: "/create_post",
-                    search: "",
-                    hash: "",
-                    key: "",
-                    state: { prevPath: this.currentLocation },
-                  }}
-                  className="nav-link"
-                  onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
-                  title={i18n.t("create_post")}
-                >
-                  {i18n.t("create_post")}
-                </NavLink>
-              </li>
-              {canCreateCommunity(this.props.siteRes) && (
-                <li className="nav-item">
-                  <NavLink
-                    to="/create_community"
-                    className="nav-link"
-                    onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
-                    title={i18n.t("create_community")}
-                  >
-                    {i18n.t("create_community")}
-                  </NavLink>
-                </li>
-              )}
-              <li className="nav-item">
-                <a
-                  className="nav-link"
-                  title={i18n.t("support_lemmy")}
-                  href={donateLemmyUrl}
-                >
-                  <Icon icon="heart" classes="small" />
-                </a>
-              </li>
-            </ul>
-            <ul className="navbar-nav my-2">
-              {amAdmin() && (
-                <li className="nav-item">
-                  <NavLink
-                    to="/admin"
-                    className="nav-link"
-                    onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
-                    title={i18n.t("admin_settings")}
-                  >
-                    <Icon icon="settings" />
-                  </NavLink>
-                </li>
-              )}
-            </ul>
-            {!this.context.router.history.location.pathname.match(
-              /^\/search/
-            ) && (
-              <ul className="navbar-nav">
-                <li className="nav-item">
-                  <NavLink
-                    to="/search"
-                    className="nav-link"
-                    title={i18n.t("search")}
-                  >
-                    <Icon icon="search" />
-                  </NavLink>
-                </li>
-              </ul>
-            )}
-            {UserService.Instance.myUserInfo ? (
-              <>
-                <ul className="navbar-nav my-2">
-                  <li className="nav-item">
-                    <NavLink
-                      className="nav-link"
-                      to="/inbox"
-                      onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
-                      title={i18n.t("unread_messages", {
-                        count: Number(this.state.unreadInboxCount),
-                        formattedCount: numToSI(this.state.unreadInboxCount),
-                      })}
-                    >
-                      <Icon icon="bell" />
-                      {this.state.unreadInboxCount > 0 && (
-                        <span className="ml-1 badge badge-light">
-                          {numToSI(this.state.unreadInboxCount)}
-                        </span>
-                      )}
-                    </NavLink>
-                  </li>
-                </ul>
-                {this.moderatesSomething && (
-                  <ul className="navbar-nav my-2">
-                    <li className="nav-item">
-                      <NavLink
-                        className="nav-link"
-                        to="/reports"
-                        onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
-                        title={i18n.t("unread_reports", {
-                          count: Number(this.state.unreadReportCount),
-                          formattedCount: numToSI(this.state.unreadReportCount),
-                        })}
-                      >
-                        <Icon icon="shield" />
-                        {this.state.unreadReportCount > 0 && (
-                          <span className="ml-1 badge badge-light">
-                            {numToSI(this.state.unreadReportCount)}
-                          </span>
-                        )}
-                      </NavLink>
-                    </li>
-                  </ul>
-                )}
-                {amAdmin() && (
-                  <ul className="navbar-nav my-2">
-                    <li className="nav-item">
-                      <NavLink
-                        to="/registration_applications"
-                        className="nav-link"
-                        onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
-                        title={i18n.t("unread_registration_applications", {
-                          count: Number(this.state.unreadApplicationCount),
-                          formattedCount: numToSI(
-                            this.state.unreadApplicationCount
-                          ),
-                        })}
-                      >
-                        <Icon icon="clipboard" />
-                        {this.state.unreadApplicationCount > 0 && (
-                          <span className="mx-1 badge badge-light">
-                            {numToSI(this.state.unreadApplicationCount)}
-                          </span>
-                        )}
-                      </NavLink>
-                    </li>
-                  </ul>
                 )}
                 {person && (
-                  <ul className="navbar-nav">
-                    <li className="nav-item dropdown">
-                      <button
-                        className="nav-link btn btn-link dropdown-toggle"
-                        onClick={linkEvent(this, this.handleToggleDropdown)}
-                        id="navbarDropdown"
-                        role="button"
-                        aria-expanded="false"
-                      >
-                        <span>
-                          {showAvatars() && person.avatar && (
-                            <PictrsImage src={person.avatar} icon />
-                          )}
-                          {person.display_name ?? person.name}
-                        </span>
-                      </button>
-                      {this.state.showDropdown && (
-                        <div
-                          className="dropdown-content"
-                          onMouseLeave={linkEvent(
-                            this,
-                            this.handleToggleDropdown
-                          )}
-                        >
-                          <li className="nav-item">
-                            <NavLink
-                              to={`/u/${person.name}`}
-                              className="nav-link"
-                              title={i18n.t("profile")}
-                            >
-                              <Icon icon="user" classes="mr-1" />
-                              {i18n.t("profile")}
-                            </NavLink>
-                          </li>
-                          <li className="nav-item">
-                            <NavLink
-                              to="/settings"
-                              className="nav-link"
-                              title={i18n.t("settings")}
-                            >
-                              <Icon icon="settings" classes="mr-1" />
-                              {i18n.t("settings")}
-                            </NavLink>
-                          </li>
-                          <li>
-                            <hr className="dropdown-divider" />
-                          </li>
-                          <li className="nav-item">
-                            <button
-                              className="nav-link btn btn-link"
-                              onClick={linkEvent(this, this.handleLogoutClick)}
-                              title="test"
-                            >
-                              <Icon icon="log-out" classes="mr-1" />
-                              {i18n.t("logout")}
-                            </button>
-                          </li>
-                        </div>
+                  <div className="dropdown">
+                    <button
+                      className="btn dropdown-toggle"
+                      role="button"
+                      aria-expanded="false"
+                      data-bs-toggle="dropdown"
+                    >
+                      {showAvatars() && person.avatar && (
+                        <PictrsImage src={person.avatar} icon />
                       )}
-                    </li>
-                  </ul>
+                      {person.display_name ?? person.name}
+                    </button>
+                    <ul
+                      className="dropdown-menu"
+                      style={{ "min-width": "fit-content" }}
+                    >
+                      <li>
+                        <NavLink
+                          to={`/u/${person.name}`}
+                          className="dropdown-item px-2"
+                          title={i18n.t("profile")}
+                          onMouseUp={linkEvent(this, handleCollapseClick)}
+                        >
+                          <Icon icon="user" classes="mr-1" />
+                          {i18n.t("profile")}
+                        </NavLink>
+                      </li>
+                      <li>
+                        <NavLink
+                          to="/settings"
+                          className="dropdown-item px-2"
+                          title={i18n.t("settings")}
+                          onMouseUp={linkEvent(this, handleCollapseClick)}
+                        >
+                          <Icon icon="settings" classes="mr-1" />
+                          {i18n.t("settings")}
+                        </NavLink>
+                      </li>
+                      <li>
+                        <hr className="dropdown-divider" />
+                      </li>
+                      <li>
+                        <button
+                          className="dropdown-item btn btn-link px-2"
+                          onClick={handleLogOut}
+                        >
+                          <Icon icon="log-out" classes="mr-1" />
+                          {i18n.t("logout")}
+                        </button>
+                      </li>
+                    </ul>
+                  </div>
                 )}
               </>
             ) : (
-              <ul className="navbar-nav my-2">
+              <>
                 <li className="nav-item">
                   <NavLink
                     to="/login"
                     className="nav-link"
-                    onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
                     title={i18n.t("login")}
+                    onMouseUp={linkEvent(this, handleCollapseClick)}
                   >
                     {i18n.t("login")}
                   </NavLink>
@@ -444,15 +423,15 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
                   <NavLink
                     to="/signup"
                     className="nav-link"
-                    onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
                     title={i18n.t("sign_up")}
+                    onMouseUp={linkEvent(this, handleCollapseClick)}
                   >
                     {i18n.t("sign_up")}
                   </NavLink>
                 </li>
-              </ul>
+              </>
             )}
-          </div>
+          </ul>
         </div>
       </nav>
     );
@@ -464,23 +443,6 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
     return amAdmin() || moderatesS;
   }
 
-  handleToggleExpandNavbar(i: Navbar) {
-    i.setState({ expanded: !i.state.expanded });
-  }
-
-  handleHideExpandNavbar(i: Navbar) {
-    i.setState({ expanded: false, showDropdown: false });
-  }
-
-  handleLogoutClick(i: Navbar) {
-    i.setState({ showDropdown: false, expanded: false });
-    UserService.Instance.logout();
-  }
-
-  handleToggleDropdown(i: Navbar) {
-    i.setState({ showDropdown: !i.state.showDropdown });
-  }
-
   parseMessage(msg: any) {
     let op = wsUserOp(msg);
     console.log(msg);
index 24b8a351c8b3c6a8616f2158b60152d8584ade4a..9432cde1c8f410ca173ace26c635a78ebecdceea 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
     picocolors "^1.0.0"
     tslib "^2.5.0"
 
-"@popperjs/core@^2.9.0":
+"@popperjs/core@^2.9.0", "@popperjs/core@^2.9.2":
   version "2.11.7"
   resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.7.tgz#ccab5c8f7dc557a52ca3288c10075c9ccd37fff7"
   integrity sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==
   dependencies:
     "@types/node" "*"
 
+"@types/bootstrap@^5.2.6":
+  version "5.2.6"
+  resolved "https://registry.yarnpkg.com/@types/bootstrap/-/bootstrap-5.2.6.tgz#e861b3aa1f4a1434da0bf50fbaa372b6f7e64d2f"
+  integrity sha512-BlAc3YATdasbHoxMoBWODrSF6qwQO/E9X8wVxCCSa6rWjnaZfpkr2N6pUMCY6jj2+wf0muUtLySbvU9etX6YqA==
+  dependencies:
+    "@popperjs/core" "^2.9.2"
+
 "@types/connect-history-api-fallback@^1.3.5":
   version "1.5.0"
   resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#9fd20b3974bdc2bcd4ac6567e2e0f6885cb2cf41"