patx/miadruck

Implement share link button and copy feature

Commit af1b6c8 · Harrison Erd · 2026-01-15T23:20:07-05:00

Changeset
af1b6c82c90093d3df67cb64fbd1e82e66a78af1
Parents
83e5e97f576342f716e9efdb53faffedef196ca0

View source at this commit

Implement share link button and copy feature

Added share link button and copy functionality with toast notification.

Comments

No comments yet.

Log in to comment

Diff

diff --git a/index.html b/index.html
index ca76b3a..e3690f1 100644
--- a/index.html
+++ b/index.html
@@ -299,6 +299,52 @@
       color:rgba(11,18,32,.92);
     }
 
+    /* --- Share link icon (bottom-left on listing cards) --- */
+    .card-actions{
+      position:relative; /* needed so the share button can anchor */
+    }
+    .link-btn{
+      position:absolute;
+      left:0;
+      bottom:0;
+      width:38px;
+      height:38px;
+      border-radius:999px;
+      border:1px solid rgba(0,0,0,.10);
+      background:rgba(255,255,255,.92);
+      display:inline-flex;
+      align-items:center;
+      justify-content:center;
+      cursor:pointer;
+      box-shadow:0 14px 34px rgba(0,0,0,.10);
+      transition:transform .12s ease, filter .12s ease, background .12s ease;
+    }
+    .link-btn:hover{ filter:brightness(1.03); transform:translateY(-1px); }
+    .link-btn:active{ transform:scale(.985); }
+    .link-btn svg{ width:18px; height:18px; }
+
+    /* Optional “Copied!” toast */
+    .copy-toast{
+      position:fixed;
+      left:50%;
+      bottom:22px;
+      transform:translateX(-50%);
+      padding:10px 14px;
+      border-radius:999px;
+      background:rgba(11,18,32,.88);
+      color:#fff;
+      font-weight:800;
+      font-size:13px;
+      z-index:999;
+      opacity:0;
+      pointer-events:none;
+      transition:opacity .18s ease, transform .18s ease;
+    }
+    .copy-toast.show{
+      opacity:1;
+      transform:translateX(-50%) translateY(-4px);
+    }
+
     .form{ display:grid; gap:12px; }
     .row2{ display:grid; grid-template-columns:1fr 1fr; gap:12px; }
     @media (max-width:560px){ .row2{ grid-template-columns:1fr; } }
@@ -953,9 +999,9 @@
   </footer>
 
   <script>
-    // ---------------------------
-    // EDITABLE DATA (no JSON files needed)
-    // ---------------------------
+    // --------------
+    // EDITABLE DATA
+    // --------------
     const FEATURED = [
       {
         id: "boca-600-nw-12",
@@ -989,13 +1035,13 @@
       },
       {
         id: "lighthouse-29-ave",
-        title: "Beach Side Cottage",
+        title: "Beach Side Cottage • Great Area",
         price: "$2,800/month",
         meta: "2 bd • 2 ba • 980 sqft",
         area: "2730 NE 29th Ave, Lighthouse Point, FL 33064",
         image: "https://i.postimg.cc/50ncVsLB/image.png",
         link: "sms:9545527330",
-        tags: ["Updated", "East of US1"],
+        tags: ["Off Market", "Updated", "East of US1"],
       }
     ];
 
@@ -1046,6 +1092,21 @@
             <div class="meta">${esc(x.area || "")}</div>
             <div class="tags">${tags}</div>
             <div class="card-actions">
+
+              <!-- bottom-left share link icon -->
+              <button class="link-btn"
+                      type="button"
+                      aria-label="Copy listing link"
+                      title="Copy link"
+                      onclick="copyListingLink('${esc(x.id || x.title)}')">
+                <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
+                  <path d="M10 13a5 5 0 0 0 7.07 0l2.12-2.12a5 5 0 0 0-7.07-7.07L10.9 4.99"
+                        stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+                  <path d="M14 11a5 5 0 0 0-7.07 0L4.81 13.12a5 5 0 0 0 7.07 7.07L13.1 19.01"
+                        stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+                </svg>
+              </button>
+
               <div class="btn-split">
                 <a href="${esc(link)}" ${newTab}>More Details</a>
                 <a href="#contact" onclick="prefillListing('${esc(x.id || x.title)}'); switchToContact();">Contact</a>
@@ -1121,6 +1182,53 @@
       if (b) b.value = v;
     }
 
+    // ---------------------------
+    // Share URL + copy helper (for link icon)
+    // ---------------------------
+    function listingShareUrl(id){
+      const u = new URL(location.href);
+      u.searchParams.set("listing", String(id || ""));
+      return u.toString();
+    }
+
+    async function copyListingLink(id){
+      const url = listingShareUrl(id);
+
+      try{
+        if (navigator.clipboard && window.isSecureContext){
+          await navigator.clipboard.writeText(url);
+        } else {
+          // fallback for non-HTTPS or older browsers
+          const ta = document.createElement("textarea");
+          ta.value = url;
+          ta.style.position = "fixed";
+          ta.style.opacity = "0";
+          document.body.appendChild(ta);
+          ta.select();
+          document.execCommand("copy");
+          ta.remove();
+        }
+        showToast("Link copied");
+      } catch (e){
+        // last resort: prompt
+        window.prompt("Copy this link:", url);
+      }
+    }
+
+    function showToast(msg){
+      let t = document.getElementById("copyToast");
+      if (!t){
+        t = document.createElement("div");
+        t.id = "copyToast";
+        t.className = "copy-toast";
+        document.body.appendChild(t);
+      }
+      t.textContent = msg || "Copied!";
+      t.classList.add("show");
+      clearTimeout(showToast._timer);
+      showToast._timer = setTimeout(() => t.classList.remove("show"), 1400);
+    }
+
     // ---------------------------
     // Formspree AJAX submit -> replace form with success (deters duplicates)
     // ---------------------------
@@ -1196,6 +1304,7 @@
     // expose for inline onclick
     window.switchToContact = switchToContact;
     window.prefillListing = prefillListing;
+    window.copyListingLink = copyListingLink;
 
     render();
   </script>