diff --git a/README.md b/README.md index 0a47d269..ffa8ab3a 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Ensure you have access to a Unix-like environment through: ## Developer Guide ### Employed Frameworks -* [Stimulus JS](https://stimulus.hotwired.dev) as the default JavaScript framework, augmenting HTML +* [Stimulus JS](https://stimulus.hotwired.dev) as the default JavaScript framework, augmenting HTML (see [the handbook](https://stimulus.hotwired.dev/handbook/origin) and [this detailed post](https://thoughtbot.com/blog/taking-the-most-out-of-stimulus) for an introduction) * [Bootstrap](https://getbootstrap.com/docs/5.2) for layout, styling and [icons](https://icons.getbootstrap.com/) * [Devise](https://github.com/heartcombo/devise) library for authentication * [FactoryBot](https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#defining-factories) to generate test data diff --git a/app/javascript/application.js b/app/javascript/application.js index 8d5575db..4ec5648f 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -9,14 +9,3 @@ import "controllers" // https://getbootstrap.com/docs/5.2/components/tooltips/ import "popper" import "bootstrap" - -/* - * Enable Bootstrap tooltips - * https://getbootstrap.com/docs/5.2/components/tooltips/#enable-tooltips - */ - -// https://turbo.hotwired.dev/reference/events -document.addEventListener('turbo:load', function () { - const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]') - const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl)) -}, false); diff --git a/app/javascript/controllers/clipboard_controller.js b/app/javascript/controllers/clipboard_controller.js new file mode 100644 index 00000000..f3dbc91b --- /dev/null +++ b/app/javascript/controllers/clipboard_controller.js @@ -0,0 +1,43 @@ +import { Controller } from "@hotwired/stimulus" + +// https://stimulus.hotwired.dev/handbook/building-something-real#implementing-a-copy-button +export default class extends Controller { + // Stimulus will automatically create target properties returning first matching target element + // this.buttonTarget & this.sourceTarget + static targets = [ "button", "source" ] + + // https://stimulus.hotwired.dev/reference/values + // pass new values in the HTML using e.g. `data-clipboard-success-duration-value="1000"` + static values = { + successDuration: { type: Number, default: 1000 }, + successMessage: { type: String, default: "Copied!" } + } + + // Stimulus calls connect() method each time a controller is connected to the document + connect() { + // https://stimulus.hotwired.dev/reference/values#properties-and-attributes + if (!this.hasButtonTarget) return + this.originalContent = this.buttonTarget.innerHTML + } + + copy(event) { + event.preventDefault() // don't follow links + const text = this.sourceTarget.innerHTML || this.sourceTarget.value + // https://www.w3.org/TR/clipboard-apis/#dom-clipboard-writetext + navigator.clipboard.writeText(text).then(() => {return this.copied()}) + } + + copied() { + if (!this.hasButtonTarget) return + + if (this.timeout) { + clearTimeout(this.timeout) + } + + this.buttonTarget.innerText = this.successMessageValue + + this.timeout = setTimeout(() => { + this.buttonTarget.innerHTML = this.originalContent + }, this.successDurationValue) + } +} diff --git a/app/javascript/controllers/hello_controller.js b/app/javascript/controllers/hello_controller.js deleted file mode 100644 index 5975c078..00000000 --- a/app/javascript/controllers/hello_controller.js +++ /dev/null @@ -1,7 +0,0 @@ -import { Controller } from "@hotwired/stimulus" - -export default class extends Controller { - connect() { - this.element.textContent = "Hello World!" - } -} diff --git a/app/javascript/controllers/tooltip_controller.js b/app/javascript/controllers/tooltip_controller.js new file mode 100644 index 00000000..25fc08ee --- /dev/null +++ b/app/javascript/controllers/tooltip_controller.js @@ -0,0 +1,25 @@ +/* + * Tooltips rely on the third party library Popper for positioning. + * Tooltips are opt-in for performance reasons, so you must initialize them yourself. + * https://getbootstrap.com/docs/5.2/components/tooltips/ + */ + +import { Controller } from "@hotwired/stimulus"; + +/* + * Connect to all elements with data-controller="tooltip" + * instead of the default `data-bs-toggle="tooltip"` + */ + +// Connects to data-controller="tooltip" HTML elements +export default class extends Controller { + connect() { + // Create a new Bootstrap Tooltip instance + // (https://getbootstrap.com/docs/5.2/components/tooltips/#methods) + // this.element is the HTML element tagged with `data-controller` + // (https://stimulus.hotwired.dev/reference/controllers#properties) + // The library reads config from `data-bs-*` attributes + // (https://getbootstrap.com/docs/5.2/components/tooltips/#directions) + bootstrap.Tooltip.getOrCreateInstance(this.element); + } +} \ No newline at end of file diff --git a/app/views/landing_page/index.html.erb b/app/views/landing_page/index.html.erb index 11618505..870dab7e 100644 --- a/app/views/landing_page/index.html.erb +++ b/app/views/landing_page/index.html.erb @@ -9,11 +9,24 @@ <% if user_signed_in? %>
- currently logged in user: <%= current_user.email %> | - <%= link_to edit_user_registration_path, class: "link-primary" do %> + <%# https://stimulus.hotwired.dev/reference/controllers %> + <%# Connect span to `app/javascript/controllers/clipboard_controller.js` %> + + <%# Stimulus marks important elements as targets to reference them in the controller through corresponding properties %> + <%# this.sourceTarget in `clipboard_controller.js` %> + Logged in user: <%= current_user.email %> + <%# In Stimulus, controller methods which handle events are called action methods %> + <%# `click->clipboard#copy` connects the button to the `copy` method in clipboard_controller.js %> + + + <%= link_to edit_user_registration_path, class: "btn btn-primary btn-sm" do %> Edit user profile - <% end %> | - <%= link_to destroy_user_session_path, data: {"turbo-method": :delete}, class: "link-secondary" do %> + <% end %> + <%= link_to destroy_user_session_path, + data: {"turbo-method": :delete, "controller": "tooltip", "bs-placement": "bottom", "bs-title": "DELETE → #{destroy_user_session_path}"}, + class: "btn btn-secondary btn-sm" do %> Log out <% end %>
@@ -39,7 +52,7 @@

Feature Number 1

Text explaining the specifics of the feature and how to use it, including details of how this improves the currently employed workflow.

- + Link with tooltip using Popper.js @@ -50,7 +63,7 @@

Feature Number 2

Text explaining the specifics of the feature and how to use it, including details of how this improves the currently employed workflow.

- + Call to action