FEATURE: Add fullscreen-tables to post (#14709)

FEATURE: Add fullscreen-tables to post (#14709)

Overflown tables will have a “expand table” option added to open x table in a modal

diff --git a/app/assets/javascripts/discourse/app/initializers/post-decorations.js b/app/assets/javascripts/discourse/app/initializers/post-decorations.js
index 8a75560..5b04730 100644
--- a/app/assets/javascripts/discourse/app/initializers/post-decorations.js
+++ b/app/assets/javascripts/discourse/app/initializers/post-decorations.js
@@ -1,11 +1,13 @@
-import { later } from "@ember/runloop";
+import { later, schedule } from "@ember/runloop";
 import I18n from "I18n";
 import highlightSyntax from "discourse/lib/highlight-syntax";
 import lightbox from "discourse/lib/lightbox";
-import { iconHTML } from "discourse-common/lib/icon-library";
+import { iconHTML, iconNode } from "discourse-common/lib/icon-library";
 import { setTextDirections } from "discourse/lib/text-direction";
 import { nativeLazyLoading } from "discourse/lib/lazy-load-images";
 import { withPluginApi } from "discourse/lib/plugin-api";
+import { create } from "virtual-dom";
+import showModal from "discourse/lib/show-modal";
 
 export default {
   name: "post-decorations",
@@ -131,6 +133,61 @@ export default {
         },
         { id: "discourse-video-codecs" }
       );
+
+      function _createButton() {
+        const openPopupBtn = document.createElement("button");
+        openPopupBtn.classList.add(
+          "open-popup-link",
+          "btn-default",
+          "btn",
+          "btn-icon-text"
+        );
+        const expandIcon = create(
+          iconNode("discourse-expand", { class: "expand-table-icon" })
+        );
+        const openPopupText = document.createTextNode(
+          I18n.t("fullscreen_table.expand_btn")
+        );
+        openPopupBtn.append(expandIcon, openPopupText);
+        return openPopupBtn;
+      }
+
+      function isOverflown({ clientWidth, scrollWidth }) {
+        return scrollWidth > clientWidth;
+      }
+
+      function generateModal(event) {
+        const table = event.target.parentNode.querySelector("table");
+        const tempTable = table.cloneNode(true);
+
+        showModal("fullscreen-table").set("tableHtml", tempTable);
+      }
+
+      function generatePopups(tables) {
+        tables.forEach((table) => {
+          if (!isOverflown(table.parentNode)) {
+            return;
+          }
+
+          const popupBtn = _createButton();
+          table.parentNode.classList.add("fullscreen-table-wrapper");
+          table.parentNode.insertBefore(popupBtn, table);
+          popupBtn.addEventListener("click", generateModal, false);
+        });
+      }
+
+      api.decorateCookedElement(
+        (post) => {
+          schedule("afterRender", () => {
+            const tables = post.querySelectorAll("table");
+            generatePopups(tables);
+          });
+        },
+        {
+          onlyStream: true,
+          id: "fullscreen-table",
+        }
+      );
     });
   },
 };
diff --git a/app/assets/javascripts/discourse/app/templates/modal/fullscreen-table.hbs b/app/assets/javascripts/discourse/app/templates/modal/fullscreen-table.hbs
new file mode 100644
index 0000000..37a0cf2
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/templates/modal/fullscreen-table.hbs
@@ -0,0 +1,3 @@
+{{#d-modal-body}}
+  {{tableHtml}}
+{{/d-modal-body}}
diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss
index cbaee44..e3b6b1e 100644
--- a/app/assets/stylesheets/common/base/topic-post.scss
+++ b/app/assets/stylesheets/common/base/topic-post.scss
@@ -1410,3 +1410,56 @@ a.mention-group {
     opacity: 0;
   }
 }
+
+.open-popup-link {
+  position: sticky;
+  left: 0.5rem;
+  top: 0.5rem;
+  opacity: 0%;
+  white-space: nowrap;
+  display: block;
+}
+
+.fullscreen-table-wrapper {
+  transition: all 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
+  display: block;
+}
+
+.expand-table-icon {
+  margin-right: 4px;
+}
+
+.fullscreen-table-modal .modal-inner-container {
+  width: max-content;
+  max-width: 90%;
+  margin: 0 auto;
+  padding: 10px;
+
+  .modal-body {
+    padding-top: 0;
+  }
+
+  thead {
+    position: sticky;
+    top: 0;
+    z-index: 1;
+    background-color: var(--secondary);
+  }
+
+  tbody {
+    overflow-x: hidden;
+  }
+
+  td {
+    padding: 0.5rem;
+  }
+}
+
+html.discourse-no-touch .fullscreen-table-wrapper:hover {
+  border-radius: 5px;
+  box-shadow: 0 2px 5px 0 rgba(var(--always-black-rgb), 0.1),
+    0 2px 10px 0 rgba(var(--always-black-rgb), 0.1);
+  .open-popup-link {
+    opacity: 100%;
+  }
+}
diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss
index ebfe944..b334d87 100644
--- a/app/assets/stylesheets/mobile/topic-post.scss
+++ b/app/assets/stylesheets/mobile/topic-post.scss
@@ -458,3 +458,8 @@ span.highlighted {
     }
   }
 }
+
+.open-popup-link {
+  opacity: 100%;
+  margin-bottom: 1rem;
+}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index d369073..67b081f 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -3938,6 +3938,9 @@ en:
 
     no_group_messages_title: "No group messages found"
 
+    fullscreen_table:
+      expand_btn: "Expand Table"
+
   # This section is exported to the javascript for i18n in the admin section
   admin_js:
     type_to_filter: "type to filter..."

GitHub sha: dd5b0543c7f8f4d4d5d4849cce98a64ae3f55f53

This commit appears in #14709 which was approved by eviltrout. It was merged by janzenisaac.