-
Notifications
You must be signed in to change notification settings - Fork 0
Convert to JS Widget #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
1abadfc
7cd1f92
29ae63b
9eb1aae
5cf81c1
230b6ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import Toolbar from "dev_toolbar/toolbar" | ||
|
|
||
| function waitForElementToExist(selector) { | ||
| return new Promise(resolve => { | ||
| if (document.querySelector(selector)) { | ||
| return resolve(document.querySelector(selector)); | ||
| } | ||
|
|
||
| const observer = new MutationObserver(() => { | ||
| if (document.querySelector(selector)) { | ||
| resolve(document.querySelector(selector)); | ||
| observer.disconnect(); | ||
| } | ||
| }); | ||
|
|
||
| observer.observe(document.body, { | ||
| subtree: true, | ||
| childList: true, | ||
| }); | ||
| }); | ||
| } | ||
| const loadEvent = self.hasOwnProperty("Turbo") ? "turbo:load" : "DOMContentLoaded"; | ||
|
|
||
| document.addEventListener(loadEvent, function() { | ||
| if (!document.getElementById("dev-toolbar")) { | ||
| Toolbar.render(); | ||
| } | ||
| waitForElementToExist("#dev-toolbar-toggle").then( () => { | ||
| document.getElementById("dev-toolbar-toggle").addEventListener("click", function() { | ||
| var links = document.getElementById("dev-toolbar-links"); | ||
| links.classList.toggle("hidden"); | ||
| }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| export default class Toolbar { | ||
| static render() { | ||
| const configuration = document.querySelector("meta[name=dev_toolbar_config]") | ||
| const defined_links = JSON.parse(configuration.content) | ||
| let toolbar_links = `` | ||
| for (let index = 0; index < defined_links.length; index++) { | ||
| const link = defined_links[index]; | ||
| toolbar_links += `<a href="${link.path}" target="_blank" class="dev-toolbar-link">${link.name}</a>` | ||
| } | ||
| const toolbar_html = ` | ||
| <div id="dev-toolbar"> | ||
| <div id="dev-toolbar-button"> | ||
| <button id="dev-toolbar-toggle">🛠️</button> | ||
| </div> | ||
| <div id="dev-toolbar-links" class="hidden"> | ||
| ${toolbar_links} | ||
| </div> | ||
| </div> | ||
| ` | ||
| document.body.insertAdjacentHTML('beforeend', toolbar_html) | ||
| } | ||
|
|
||
| } | ||
| export { Toolbar } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| #dev-toolbar { | ||
| position: fixed; | ||
| right: 0; | ||
| top: 50vh; | ||
| transform: translateY(-50%); | ||
| background-color: #f0f0f0; | ||
| border: 1px solid #ccc; | ||
| z-index: 1000; | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: center; | ||
| font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif; | ||
| color: #808080; | ||
| } | ||
|
|
||
| #dev-toolbar-toggle { | ||
| all: unset; | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed the toolbar icon from a link to a button, since clicking on it doesn't navigate to another (part of the) page. |
||
| font-size: 2em; | ||
| border: none; | ||
| cursor: pointer; | ||
| line-height: 1.5; | ||
| padding: 0 10px; | ||
| text-decoration: none; | ||
| } | ||
|
|
||
| #dev-toolbar-links { | ||
| display: flex; | ||
| flex-direction: column; | ||
| } | ||
|
|
||
| .dev-toolbar-link { | ||
| padding: 5px 10px; | ||
| border-bottom: 1px #f0f0f0 solid; | ||
| color: #808080; | ||
| text-decoration: none; | ||
| background-color: white; | ||
| } | ||
|
|
||
| #dev-toolbar-links.hidden { | ||
| display: none; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ class ErdController < ActionController::Base | |
|
|
||
| def show | ||
| @erd_path = Rails.root.join("erd.png") | ||
| render :show | ||
| render "dev_toolbar/erd/show", formats: [:html] | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Rails app was not finding this view template until I specified it with this default. I don't this this should be necessary, but I wasn't able to figure it out. I'd love to learn why the previous way wasn't working.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also looked into this for a bit, but wasn't able to figure it out. Claude 4.7 sent me down some paths, which were all wrong in the end. This is a weird one, but I'm going to leave it alone now. |
||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,65 +10,10 @@ def call(env) | |
| if Rails.env.development? && headers["Content-Type"]&.include?("text/html") | ||
| response_body = response.body | ||
| toolbar_html = <<-HTML | ||
| <div id="dev-toolbar"> | ||
| <div id="dev-toolbar-button"> | ||
| <a id="dev-toolbar-toggle">🛠️</a> | ||
| </div> | ||
| <div id="dev-toolbar-links" class="hidden"> | ||
| #{toolbar_links} | ||
| </div> | ||
| </div> | ||
| <style> | ||
| #dev-toolbar { | ||
| position: fixed; | ||
| right: 0; | ||
| top: 50vh; | ||
| transform: translateY(-50%); | ||
| background-color: #f0f0f0; | ||
| border: 1px solid #ccc; | ||
| z-index: 1000; | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: center; | ||
| font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif; | ||
| color: #808080; | ||
| } | ||
|
|
||
| #dev-toolbar-toggle { | ||
| font-size: 2em; | ||
| border: none; | ||
| cursor: pointer; | ||
| line-height: 1.5; | ||
| padding: 0 10px; | ||
| text-decoration: none; | ||
| } | ||
|
|
||
| #dev-toolbar-links { | ||
| display: flex; | ||
| flex-direction: column; | ||
| } | ||
|
|
||
| .dev-toolbar-link { | ||
| padding: 5px 10px; | ||
| border-bottom: 1px #f0f0f0 solid; | ||
| color: #808080; | ||
| text-decoration: none; | ||
| background-color: white; | ||
| } | ||
|
|
||
| #dev-toolbar-links.hidden { | ||
| display: none; | ||
| } | ||
| </style> | ||
| <script> | ||
| document.getElementById('dev-toolbar-toggle').addEventListener('click', function() { | ||
| var links = document.getElementById('dev-toolbar-links'); | ||
| links.classList.toggle('hidden'); | ||
| }); | ||
| </script> | ||
| <meta name="dev_toolbar_config" content='#{toolbar_links_content}'> | ||
|
jelaniwoods marked this conversation as resolved.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The configured toolbar links needed to be passed from the initializer to the JavaScript file somehow so I decided to store them in a meta tag as JSON. Since it's in the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this is very small and discrete in the source.
jelaniwoods marked this conversation as resolved.
jelaniwoods marked this conversation as resolved.
|
||
| HTML | ||
|
jelaniwoods marked this conversation as resolved.
|
||
|
|
||
| response_body.sub!('</body>', "#{toolbar_html}</body>") | ||
| response_body.sub!('</head>', "#{toolbar_html}</head>") | ||
| headers["Content-Length"] = response_body.bytesize.to_s | ||
|
|
||
| response = [response_body] | ||
|
|
@@ -79,15 +24,8 @@ def call(env) | |
|
|
||
| private | ||
|
|
||
| def toolbar_links | ||
| DevToolbar.configuration.links.map do |link| | ||
| # if the erd.png file does not exist in /public, don't show the link | ||
| if link[:name] == "ERD" && !File.exist?(Rails.root.join("erd.png")) | ||
| next | ||
| else | ||
| "<a href='#{link[:path]}' target='_blank' class='dev-toolbar-link'>#{link[:name]}</a>" | ||
| end | ||
| end.compact.join(" ") | ||
| def toolbar_links_content | ||
| JSON.generate(DevToolbar.configuration.links) | ||
| end | ||
| end | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Toolbar.render()always appends a new#dev-toolbarnode withinsertAdjacentHTML, so after Turbo restores a cached page (for example, browser Back/Forward) and firesturbo:loadagain, the page accumulates duplicate toolbars and duplicated toggle controls. This regression was introduced by moving rendering client-side without a guard/removal step; add an existence check (or remove before cache) so repeated loads do not duplicate UI.Useful? React with 👍 / 👎.