avo-hq / avo

Build Ruby on Rails apps 10x faster
https://avohq.io
Other
1.53k stars 256 forks source link

Click to copy field option #2769

Open adrianthedev opened 6 months ago

adrianthedev commented 6 months ago

Feature

We'd love to have a Click to copy field option.

Similar PR https://github.com/avo-hq/avo/issues/2771

Current workarounds

Custom field.

Screenshots or screen recordings

CleanShot 2024-05-23 at 10 36 56@2x

Additional context

Part of the code I used to get the screenshot. The @index part need to be taken out.

      <% if on_show? %>
        <% if field.value.blank? and dash_if_blank %>
          —
        <% else %>
        <div class="flex">
          <% if @index.in?([1,5]) %>
          <span class="flex-1"><%= content %></span>
          <a href="javascript:void(0)" class=" text-xs">
            <%= helpers.svg 'heroicons/outline/clipboard', class: "h-4 inline" %> click to copy
          </a>
        <% end %>
        </div>
        <% end %>

This is a JS controller we use on avohq.io (on the hero section)

import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
  static targets = ['trigger']

  copy() {
    const initialContent = this.triggerTarget.innerHTML

    const str = this.context.element.dataset.text
    /* ——— Derived from: https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f
          improved to add iOS device compatibility——— */
    const el = document.createElement('textarea'); // Create a <textarea> element

    let storeContentEditable = el.contentEditable;
    let storeReadOnly = el.readOnly;

    el.value = str; // Set its value to the string that you want copied
    el.contentEditable = true;
    el.readOnly = false;
    el.setAttribute('readonly', false); // Make it readonly false for iOS compatability
    el.setAttribute('contenteditable', true); // Make it editable for iOS
    el.style.position = 'absolute';
    el.style.left = '-9999px'; // Move outside the screen to make it invisible
    document.body.appendChild(el); // Append the <textarea> element to the HTML document
    const selected =
        document.getSelection().rangeCount > 0 // Check if there is any content selected previously
            ? document.getSelection().getRangeAt(0) // Store selection if found
            : false; // Mark as false to know no selection existed before
    el.select(); // Select the <textarea> content
    el.setSelectionRange(0, 999999);
    document.execCommand('copy'); // Copy - only works as a result of a user action (e.g. click events)
    document.body.removeChild(el); // Remove the <textarea> element
    if (selected) {
        // If a selection existed before copying
        document.getSelection().removeAllRanges(); // Unselect everything on the HTML document
        document.getSelection().addRange(selected); // Restore the original selection
    }

    el.contentEditable = storeContentEditable;
    el.readOnly = storeReadOnly;

    const target = this.triggerTarget
    target.innerHTML = 'Copied 👌'
    target.classList.add('transition', 'opacity-80', 'bg-green-100')

    setTimeout(() => {
      target.innerHTML = initialContent
      target.classList.remove('opacity-80', 'bg-green-100')
    }, 1500);
  }
}
Paul-Bob commented 6 months ago

This can be an option for existing fields ( like text, text_area and some more text related fields) where click_to_copy: true makes that clipboard button appear.

adrianthedev commented 6 months ago

Yes. That too!

Paul-Bob commented 6 months ago

Let's explore https://www.stimulus-components.com/docs/stimulus-clipboard