rails-markup 1.4.7 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +34 -7
- data/app/assets/javascripts/rails_markup/toolbar/10-styles.js +104 -62
- data/app/assets/javascripts/rails_markup/toolbar/20-dom.js +31 -17
- data/app/assets/javascripts/rails_markup/toolbar/40-events.js +71 -26
- data/app/assets/javascripts/rails_markup/toolbar/50-sync.js +2 -2
- data/app/assets/javascripts/rails_markup/toolbar/60-render.js +128 -69
- data/app/assets/javascripts/rails_markup/toolbar/90-init.js +13 -0
- data/app/views/layouts/rails_markup/application.html.erb +17 -123
- data/app/views/rails_markup/dashboard/_annotation_card.html.erb +4 -8
- data/app/views/rails_markup/dashboard/_annotation_list.html.erb +4 -0
- data/app/views/rails_markup/dashboard/_feedback_modal.html.erb +4 -0
- data/app/views/rails_markup/dashboard/_filters.html.erb +31 -22
- data/app/views/rails_markup/dashboard/_modal_navigation.html.erb +81 -0
- data/app/views/rails_markup/dashboard/_styles.html.erb +118 -36
- data/app/views/rails_markup/dashboard/_toolbar_preferences.html.erb +32 -0
- data/app/views/rails_markup/dashboard/board.html.erb +42 -55
- data/app/views/rails_markup/dashboard/index.html.erb +5 -23
- data/app/views/rails_markup/dashboard/show.html.erb +10 -8
- data/lib/rails_markup/configuration.rb +3 -4
- data/lib/rails_markup/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 416325893f5bb2e30eb526929e41c2aee847d77e078099f7b1530cc512549666
|
|
4
|
+
data.tar.gz: ee02f54d6d604e37fe2d1d32fd779d5cf1d1a0d677a127b1b6ba22e5cb226b0b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e3036a905792755633c1e5bb4f0c65bc7adf8c3d1b8d0b360200e2a959177180986ac85fa86fa20a1840d50b2067709a34d1763c6d1a1ea82793970d479694ff
|
|
7
|
+
data.tar.gz: 183df16f69b58db0ed2c6a3d1654073344c48c442f6fbcf43a8765b2f3c1df0bf907a6c43c488deb8d87ea9534a81f376e2bba1b1c2b97bbc0ae0eb067f6ee3f
|
data/README.md
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
Point-and-click annotation tool for Rails apps. Click any element, describe what needs to change, and your AI agent reads and acts on your feedback via MCP.
|
|
4
4
|
|
|
5
|
+
Built with love in Sydney by [Nauman Tariq](https://nauman.one) and Pavelabs.
|
|
6
|
+
|
|
5
7
|
**v1.0** — Author attribution, export, search, screenshots with drawing tools, kanban board, notification hooks.
|
|
6
8
|
|
|
7
9
|
## How it works
|
|
8
10
|
|
|
9
11
|
1. **Install the gem** — adds migration, toolbar, auth controller, and routes
|
|
10
12
|
2. **Open your app** — the annotation toolbar appears as a floating button
|
|
11
|
-
3. **Click any element** — hover to highlight, click to annotate
|
|
12
|
-
4. **Draw on screenshots** — arrows, rectangles, highlights on
|
|
13
|
+
3. **Click any element** — hover to highlight, click to annotate, optionally attach a screenshot
|
|
14
|
+
4. **Draw on screenshots** — arrows, rectangles, highlights on attached images
|
|
13
15
|
5. **Agent reads it** — AI calls `rails_markup_read` via MCP
|
|
14
16
|
6. **Agent fixes it** — resolves the annotation and moves on
|
|
15
17
|
|
|
@@ -17,7 +19,7 @@ Point-and-click annotation tool for Rails apps. Click any element, describe what
|
|
|
17
19
|
|
|
18
20
|
```ruby
|
|
19
21
|
# Gemfile
|
|
20
|
-
gem "rails-markup",
|
|
22
|
+
gem "rails-markup", require: "rails_markup"
|
|
21
23
|
```
|
|
22
24
|
|
|
23
25
|
```bash
|
|
@@ -156,7 +158,7 @@ RailsMarkup.configure do |config|
|
|
|
156
158
|
config.toolbar_position = "bl"
|
|
157
159
|
config.toolbar_size = "default"
|
|
158
160
|
|
|
159
|
-
#
|
|
161
|
+
# Optional image attachments (default: true)
|
|
160
162
|
config.enable_screenshots = true
|
|
161
163
|
|
|
162
164
|
# Dashboard pagination (default: 25)
|
|
@@ -174,7 +176,7 @@ Visit `/admin/rails-markup` for the full dashboard:
|
|
|
174
176
|
- **List view** — status filters, search, author filter, load-more pagination
|
|
175
177
|
- **Board view** — kanban with drag-and-drop status transitions
|
|
176
178
|
- **Export** — CSV and JSON downloads (respects current filters)
|
|
177
|
-
- **
|
|
179
|
+
- **Shared feedback modal** — list and board open the same full content, context, images and thread; Escape, Close or the backdrop returns to your current view
|
|
178
180
|
- **Bulk actions** — dismiss all pending/acknowledged
|
|
179
181
|
|
|
180
182
|
### Search & Filters
|
|
@@ -184,15 +186,19 @@ Visit `/admin/rails-markup` for the full dashboard:
|
|
|
184
186
|
- **Page URL filter** — filter by annotated page
|
|
185
187
|
- **Status pills** — pending, acknowledged, resolved, dismissed
|
|
186
188
|
|
|
189
|
+
Open **Options** for page/author filters, exports and the **Floating toolbar** switch. This browser preference hides or shows the entire floating control group and syncs across open tabs. Board help lives under the info icon; each card's **Move** disclosure provides a touch-friendly alternative to dragging.
|
|
190
|
+
|
|
187
191
|
## Screenshots & Drawing
|
|
188
192
|
|
|
189
|
-
|
|
193
|
+
After selecting an element, choose **Capture tab** to use the browser screen-sharing picker, **Upload image** (PNG, JPEG, or WebP under 5 MB), or paste an image into the feedback field. Native capture requires browser support and permission each time; the video stream stops immediately after a single frame is captured. No image is submitted until you submit the feedback. Preview or remove an attachment before submitting, and draw on it:
|
|
190
194
|
|
|
191
195
|
- **Arrow** — click and drag to draw red arrows
|
|
192
196
|
- **Rectangle** — click and drag for red outline boxes
|
|
193
197
|
- **Highlight** — freehand semi-transparent yellow strokes
|
|
194
198
|
- **Undo** — remove the last drawing operation
|
|
195
199
|
|
|
200
|
+
The engine dashboard’s **Floating toolbar** switch shows or hides the entire dock for this browser, including across open tabs. Pins and synchronization remain active.
|
|
201
|
+
|
|
196
202
|
Screenshots are stored as base64 in annotation metadata and displayed in the dashboard detail view.
|
|
197
203
|
|
|
198
204
|
## CLI
|
|
@@ -320,9 +326,30 @@ Browser Toolbar AI Agent (Claude Code, Cursor)
|
|
|
320
326
|
```bash
|
|
321
327
|
git clone https://github.com/nauman/rails-markup
|
|
322
328
|
cd rails-markup && bundle install
|
|
323
|
-
bundle exec
|
|
329
|
+
bundle exec rake test
|
|
330
|
+
node --test test/javascript/*_test.mjs
|
|
331
|
+
bundle exec rake test:system # requires Chrome
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Local demo
|
|
335
|
+
|
|
336
|
+
Run the included host app with the gem loaded from this checkout:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
bundle exec ruby script/demo
|
|
324
340
|
```
|
|
325
341
|
|
|
342
|
+
Open [the demo login](http://127.0.0.1:4317/rails_markup_test_session/new) and
|
|
343
|
+
click **Authenticate**, then visit [the host page](http://127.0.0.1:4317/host).
|
|
344
|
+
Click the floating button once to expand the tools, click it again to annotate,
|
|
345
|
+
then click an element and add feedback. The same annotation appears in
|
|
346
|
+
[the dashboard](http://127.0.0.1:4317/feedback); resolve it there and reload the
|
|
347
|
+
host page to see the updated status and thread.
|
|
348
|
+
|
|
349
|
+
The demo binds to loopback, uses a test-only login, enables CSRF protection,
|
|
350
|
+
and keeps its SQLite database in `tmp/demo/annotations.sqlite3`. Set `PORT` to
|
|
351
|
+
change the port. Stop with Ctrl-C; remove that database to reset demo data.
|
|
352
|
+
|
|
326
353
|
## License
|
|
327
354
|
|
|
328
355
|
MIT. See [LICENSE](LICENSE).
|
|
@@ -9,83 +9,125 @@
|
|
|
9
9
|
@keyframes rm-toast-out { from{opacity:1;transform:translateY(0) scale(1)} to{opacity:0;transform:translateY(16px) scale(0.95)} }
|
|
10
10
|
#rm-toolbar-root { position:fixed; inset:0; pointer-events:none; z-index:9979; }
|
|
11
11
|
#rm-toolbar-root * { box-sizing:border-box; font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",sans-serif; }
|
|
12
|
-
|
|
13
|
-
.rm-
|
|
14
|
-
.rm-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
.rm-
|
|
18
|
-
|
|
19
|
-
.rm-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.rm-
|
|
25
|
-
.rm-
|
|
26
|
-
|
|
12
|
+
#rm-toolbar-root .rm-dock, #rm-toolbar-root .rm-panel, #rm-toolbar-root .rm-popup { pointer-events:auto; }
|
|
13
|
+
#rm-toolbar-root .rm-dock { position:fixed; z-index:9980; display:flex; align-items:center; padding:4px; border:1px solid var(--rm-accent-hover); border-radius:14px; background:var(--rm-accent); color:#fff; box-shadow:0 6px 20px #0003,0 1px 3px #0002; }
|
|
14
|
+
#rm-toolbar-root .rm-dock button { position:static; display:flex; align-items:center; justify-content:center; gap:6px; flex-shrink:0; min-width:var(--rm-control-size); height:var(--rm-control-size); margin:0; padding:0 10px; border:0; border-radius:10px; background:transparent; color:#e5e7eb; cursor:pointer; box-shadow:none; appearance:none; transition:background .15s,color .15s; }
|
|
15
|
+
#rm-toolbar-root .rm-dock button:hover { background:#ffffff18; color:#fff; }
|
|
16
|
+
#rm-toolbar-root .rm-dock button:focus-visible { outline:2px solid #fff; outline-offset:2px; }
|
|
17
|
+
#rm-toolbar-root .rm-dock button.rm-fab { background:var(--rm-accent); color:#fff; }
|
|
18
|
+
#rm-toolbar-root .rm-dock button.rm-fab:hover { background:var(--rm-accent-hover); }
|
|
19
|
+
#rm-toolbar-root .rm-dock[data-state="annotating"] button.rm-fab { box-shadow:inset 0 0 0 2px #ffffff80; }
|
|
20
|
+
#rm-toolbar-root .rm-dock svg { width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round; }
|
|
21
|
+
#rm-toolbar-root .rm-dock-controls { display:flex; align-items:center; gap:2px; margin-left:4px; padding-left:4px; border-left:1px solid #ffffff26; }
|
|
22
|
+
#rm-toolbar-root .rm-dock-controls[hidden] { display:none; }
|
|
23
|
+
#rm-toolbar-root .rm-panel-toggle { order:0; }
|
|
24
|
+
#rm-toolbar-root .rm-toolbar-settings { order:1; }
|
|
25
|
+
#rm-toolbar-root .rm-dock-close { order:2; }
|
|
26
|
+
#rm-toolbar-root .rm-panel-toggle-badge { font-size:11px; font-weight:600; font-variant-numeric:tabular-nums; color:#e5e7eb; }
|
|
27
|
+
@media (prefers-reduced-motion:reduce) { #rm-toolbar-root .rm-dock button { transition:none; } }
|
|
28
|
+
#rm-toolbar-root .rm-toast-container { position:fixed; z-index:9983; display:flex; flex-direction:column; gap:8px; pointer-events:none; }
|
|
29
|
+
#rm-pins-container { position:absolute; top:0; left:0; width:100%; z-index:9979; pointer-events:none; }
|
|
30
|
+
#rm-pins-container .rm-pin { pointer-events:auto; }
|
|
31
|
+
#rm-toolbar-root .rm-popup { max-height:calc(100vh - 24px); overflow-y:auto; display:none; position:fixed; z-index:9982; width:360px; max-width:calc(100vw - 24px); background:#fff; border-radius:16px; box-shadow:0 18px 48px #18213824,0 2px 6px #1821380a; border:1px solid #dce1e8; padding:16px; }
|
|
27
32
|
#rm-toolbar-root .rm-popup textarea { display:block; width:100%; max-width:100%; font-size:13px; font-weight:400; line-height:1.4; color:#1f2937; height:auto; margin:0; border:1px solid #e5e7eb; border-radius:12px; padding:12px; resize:none; outline:none; font-family:inherit; background:#fff; background-image:none; box-shadow:none; appearance:none; -webkit-appearance:none; transition:border-color 0.15s,box-shadow 0.15s; }
|
|
28
33
|
#rm-toolbar-root .rm-popup textarea:focus { border:1px solid #818cf8; box-shadow:0 0 0 3px rgba(99,102,241,0.1); }
|
|
29
34
|
#rm-toolbar-root .rm-menu { position:relative; display:inline-block; vertical-align:middle; }
|
|
30
|
-
#rm-toolbar-root .rm-menu-btn { display:inline-flex; align-items:center; gap:4px; width:auto; height:auto; margin:0; font-size:11px; font-weight:500; line-height:1.4; color:#374151; border:1px solid #e5e7eb; border-radius:8px; padding:6px 8px; background:#fff; background-image:none; box-shadow:none; outline:none; text-transform:none; appearance:none; -webkit-appearance:none; cursor:pointer; }
|
|
35
|
+
#rm-toolbar-root .rm-menu-btn { min-height:32px; display:inline-flex; align-items:center; gap:4px; width:auto; height:auto; margin:0; font-size:11px; font-weight:500; line-height:1.4; color:#374151; border:1px solid #e5e7eb; border-radius:8px; padding:6px 8px; background:#fff; background-image:none; box-shadow:none; outline:none; text-transform:none; appearance:none; -webkit-appearance:none; cursor:pointer; }
|
|
31
36
|
#rm-toolbar-root .rm-menu-btn:hover { border-color:#d1d5db; background:#fff; }
|
|
32
37
|
#rm-toolbar-root .rm-menu-btn:focus { outline:none; border-color:#818cf8; box-shadow:0 0 0 3px rgba(99,102,241,0.1); }
|
|
33
38
|
#rm-toolbar-root .rm-menu-btn[aria-expanded="true"] { border-color:#818cf8; }
|
|
34
39
|
#rm-toolbar-root .rm-menu-chevron { width:10px; height:10px; flex-shrink:0; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; opacity:0.55; }
|
|
35
40
|
#rm-toolbar-root .rm-menu-list { display:none; position:absolute; top:calc(100% + 4px); left:0; z-index:9984; min-width:100%; padding:4px; margin:0; list-style:none; background:#fff; border:1px solid #e5e7eb; border-radius:10px; box-shadow:0 10px 24px rgba(0,0,0,0.12); }
|
|
36
41
|
#rm-toolbar-root .rm-menu-list.rm-menu-open { display:block; }
|
|
37
|
-
#rm-toolbar-root .rm-menu-option { display:block; width:100%; margin:0; padding:6px 10px; font-size:11px; font-weight:500; line-height:1.4; color:#374151; text-align:left; border:none; border-radius:6px; background:transparent; background-image:none; box-shadow:none; cursor:pointer; appearance:none; -webkit-appearance:none; }
|
|
42
|
+
#rm-toolbar-root .rm-menu-option { min-height:32px; display:block; width:100%; margin:0; padding:6px 10px; font-size:11px; font-weight:500; line-height:1.4; color:#374151; text-align:left; border:none; border-radius:6px; background:transparent; background-image:none; box-shadow:none; cursor:pointer; appearance:none; -webkit-appearance:none; }
|
|
38
43
|
#rm-toolbar-root .rm-menu-option:hover, #rm-toolbar-root .rm-menu-option:focus { background:#f3f4f6; outline:none; }
|
|
39
44
|
#rm-toolbar-root .rm-menu-option-active { background:#eef2ff; color:#4338ca; }
|
|
40
|
-
#rm-toolbar-root .rm-menu-compact .rm-menu-btn { font-size:
|
|
45
|
+
#rm-toolbar-root .rm-menu-compact .rm-menu-btn { font-size:11px; min-height:28px; padding:4px 7px; border-radius:4px; color:#6b7280; }
|
|
41
46
|
#rm-toolbar-root .rm-menu-compact .rm-menu-list, #rm-toolbar-root .rm-menu-list-compact { min-width:120px; right:0; left:auto; }
|
|
42
47
|
#rm-toolbar-root .rm-menu-compact .rm-menu-option, #rm-toolbar-root .rm-menu-list-compact .rm-menu-option { font-size:10px; padding:5px 8px; }
|
|
43
|
-
.rm-popup-el { font-size:11px; color:#
|
|
44
|
-
.rm-popup-text { font-size:12px; color:#6b7280; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; margin-top:2px; line-height:1.4; }
|
|
45
|
-
.rm-popup-actions { display:flex; align-items:center; gap:8px; margin-top:8px; }
|
|
46
|
-
.rm-popup-actions .rm-count { font-size:
|
|
47
|
-
#rm-toolbar-root .rm-btn-cancel { padding:
|
|
48
|
+
#rm-toolbar-root .rm-popup-el { font-size:11px; color:#596579; font-family:monospace; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; line-height:1.4; }
|
|
49
|
+
#rm-toolbar-root .rm-popup-text { font-size:12px; color:#6b7280; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; margin-top:2px; line-height:1.4; }
|
|
50
|
+
#rm-toolbar-root .rm-popup-actions { display:flex; justify-content:flex-end; align-items:center; gap:8px; margin-top:8px; }
|
|
51
|
+
#rm-toolbar-root .rm-popup-actions .rm-count { font-size:11px; color:#596579; margin-left:auto; font-variant-numeric:tabular-nums; }
|
|
52
|
+
#rm-toolbar-root .rm-btn-cancel { min-height:36px; padding:8px 12px; font-size:12px; color:#596579; background:none; background-image:none; border:none; box-shadow:none; cursor:pointer; border-radius:8px; appearance:none; -webkit-appearance:none; }
|
|
48
53
|
#rm-toolbar-root .rm-btn-cancel:hover { color:#6b7280; }
|
|
49
|
-
#rm-toolbar-root .rm-btn-submit { padding:
|
|
54
|
+
#rm-toolbar-root .rm-btn-submit { min-height:36px; padding:8px 16px; font-size:12px; font-weight:500; color:#fff; border:none; border-radius:8px; cursor:pointer; display:inline-flex; align-items:center; gap:6px; box-shadow:none; appearance:none; -webkit-appearance:none; }
|
|
50
55
|
#rm-toolbar-root .rm-btn-submit kbd { font-size:9px; opacity:0.6; font-family:sans-serif; }
|
|
51
|
-
.rm-panel { display:none; position:fixed; z-index:9981; width:380px; max-width:calc(100vw - 48px); max-height:
|
|
52
|
-
.rm-panel-header { display:flex; align-items:center; justify-content:space-between; padding:
|
|
53
|
-
.rm-panel-header h3 { font-size:
|
|
54
|
-
.rm-panel-header-actions { display:flex; align-items:center; gap:6px; }
|
|
55
|
-
.rm-panel-count { min-width:20px; text-align:center; padding:2px 6px; font-size:10px; font-weight:600; border-radius:10px; }
|
|
56
|
-
.rm-settings { padding:
|
|
57
|
-
.rm-settings[hidden] { display:none; }
|
|
58
|
-
.rm-
|
|
59
|
-
|
|
60
|
-
.rm-
|
|
61
|
-
.rm-
|
|
62
|
-
.rm-
|
|
63
|
-
.rm-
|
|
64
|
-
.rm-
|
|
65
|
-
.rm-
|
|
66
|
-
.rm-
|
|
67
|
-
|
|
68
|
-
.rm-
|
|
69
|
-
.rm-panel-
|
|
70
|
-
.rm-panel-
|
|
71
|
-
.rm-
|
|
72
|
-
.rm-
|
|
73
|
-
.rm-
|
|
74
|
-
.rm-
|
|
75
|
-
.rm-
|
|
76
|
-
.rm-
|
|
77
|
-
.rm-
|
|
78
|
-
.rm-
|
|
79
|
-
.rm-
|
|
80
|
-
.rm-
|
|
81
|
-
.rm-
|
|
82
|
-
.rm-
|
|
83
|
-
|
|
84
|
-
.rm-
|
|
85
|
-
|
|
86
|
-
.rm-
|
|
87
|
-
.rm-
|
|
88
|
-
|
|
56
|
+
#rm-toolbar-root .rm-panel { display:none; position:fixed; z-index:9981; width:380px; max-width:calc(100vw - 48px); max-height: min(560px, calc(100vh - 100px)); overflow:hidden; background:#fff; border-radius:16px; box-shadow:0 18px 48px #18213824,0 2px 6px #1821380a; border:1px solid #dce1e8; flex-direction:column; }
|
|
57
|
+
#rm-toolbar-root .rm-panel-header { display:flex; align-items:center; justify-content:space-between; padding:16px; border-bottom:1px solid #e5e7eb; }
|
|
58
|
+
#rm-toolbar-root .rm-panel-header h3 { margin:0; font-size:15px; font-weight:600; color:#1f2937; }
|
|
59
|
+
#rm-toolbar-root .rm-panel-header-actions { display:flex; align-items:center; gap:6px; }
|
|
60
|
+
#rm-toolbar-root .rm-panel-count { min-width:20px; text-align:center; padding:2px 6px; font-size:10px; font-weight:600; border-radius:10px; }
|
|
61
|
+
#rm-toolbar-root .rm-settings { padding:16px; overflow-y:auto; }
|
|
62
|
+
#rm-toolbar-root .rm-settings[hidden] { display:none; }
|
|
63
|
+
#rm-toolbar-root .rm-image-options { margin:8px 0; }
|
|
64
|
+
#rm-toolbar-root .rm-image-options:not([open]) > :not(summary) { display:none; }
|
|
65
|
+
#rm-toolbar-root .rm-image-options[hidden] { display:none; }
|
|
66
|
+
#rm-toolbar-root .rm-image-options > summary { cursor:pointer;color:#64748b;font-size:12px;padding:5px 0; }
|
|
67
|
+
#rm-toolbar-root .rm-screenshot-actions { display:flex;flex-wrap:wrap;gap:8px;margin:12px 0; }
|
|
68
|
+
#rm-toolbar-root .rm-screenshot-actions[hidden], #rm-toolbar-root .rm-screenshot-actions [hidden] { display:none; }
|
|
69
|
+
#rm-toolbar-root .rm-screenshot-actions button { border:1px solid #dce1e8;border-radius:7px;padding:7px 10px;background:#fff;color:#334155;font-size:12px;cursor:pointer; }
|
|
70
|
+
#rm-toolbar-root .rm-drawing-tools button { border:1px solid #dce1e8;border-radius:7px;background:#fff;color:#334155;cursor:pointer; }
|
|
71
|
+
#rm-toolbar-root .rm-screenshot-actions span { flex-basis:100%;font-size:11px;line-height:1.5;color:#596579; }
|
|
72
|
+
|
|
73
|
+
#rm-toolbar-root .rm-panel[data-view="settings"] .rm-panel-count,
|
|
74
|
+
#rm-toolbar-root .rm-panel[data-view="settings"] .rm-filter-chips,
|
|
75
|
+
#rm-toolbar-root .rm-panel[data-view="settings"] .rm-panel-list,
|
|
76
|
+
#rm-toolbar-root .rm-panel[data-view="settings"] .rm-panel-footer { display:none; }
|
|
77
|
+
#rm-toolbar-root .rm-setting-choice { border:1px solid #e2e6ec; border-radius:8px; padding:9px 12px; background:#fff; color:#475569; font-size:12px; cursor:pointer; }
|
|
78
|
+
#rm-toolbar-root .rm-setting-choice[aria-pressed="true"] { background:#eef1f5; border-color:#8995a5; color:#172033; box-shadow:inset 0 0 0 1px #8995a5; }
|
|
79
|
+
#rm-toolbar-root .rm-color-swatch { width:36px; height:36px; padding:0; border:3px solid #fff; border-radius:50%; color:#fff; font-size:17px; }
|
|
80
|
+
#rm-toolbar-root .rm-color-swatch[aria-pressed="true"] { color:#fff; box-shadow:0 0 0 2px #64748b; border-color:#fff; }
|
|
81
|
+
#rm-toolbar-root .rm-corner-choice { font-size:24px; width:54px; padding:4px; }
|
|
82
|
+
#rm-toolbar-root .rm-settings-group.rm-settings-switch-row { flex-direction:row; align-items:center; justify-content:space-between; padding-top:16px; border-top:1px solid #eef1f5; }
|
|
83
|
+
#rm-toolbar-root .rm-setting-switch { width:38px; height:22px; padding:3px; border:0; border-radius:20px; background:#94a3b8; cursor:pointer; }
|
|
84
|
+
#rm-toolbar-root .rm-setting-switch span { display:block; width:16px; height:16px; background:#fff; border-radius:50%; }
|
|
85
|
+
#rm-toolbar-root .rm-setting-switch[aria-checked="true"] { background:#475569; }
|
|
86
|
+
#rm-toolbar-root .rm-setting-switch[aria-checked="true"] span { transform:translateX(16px); }
|
|
87
|
+
#rm-toolbar-root .rm-setting-choice:focus-visible, #rm-toolbar-root .rm-setting-switch:focus-visible { outline:2px solid #475569; outline-offset:3px; }
|
|
88
|
+
|
|
89
|
+
#rm-toolbar-root .rm-settings-group { display:flex; flex-direction:column; gap:8px; margin-bottom:14px; }
|
|
90
|
+
#rm-toolbar-root .rm-settings-label { font-size:12px; font-weight:600; color:#516074; }
|
|
91
|
+
#rm-toolbar-root .rm-settings-options { display:flex; flex-wrap:wrap; gap:6px; }
|
|
92
|
+
#rm-toolbar-root .rm-panel-close { min-width:32px; min-height:32px; padding:8px; color:#596579; background:none; border:none; cursor:pointer; border-radius:8px; }
|
|
93
|
+
#rm-toolbar-root .rm-panel-close:hover { color:#6b7280; }
|
|
94
|
+
#rm-toolbar-root .rm-panel-close svg { width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
|
|
95
|
+
#rm-toolbar-root .rm-filter-chips { display:flex; gap:6px; padding:10px 16px; border-bottom:1px solid #f9fafb; }
|
|
96
|
+
#rm-toolbar-root .rm-chip { min-height:32px; padding:6px 10px; font-size:12px; font-weight:500; border-radius:10px; cursor:pointer; transition:all 0.15s; border:none; }
|
|
97
|
+
#rm-toolbar-root .rm-chip-active { color:#fff; }
|
|
98
|
+
#rm-toolbar-root .rm-chip-inactive { background:#f9fafb; color:#596579; }
|
|
99
|
+
#rm-toolbar-root .rm-chip-inactive:hover { color:#6b7280; }
|
|
100
|
+
#rm-toolbar-root .rm-panel-list { flex:1; min-height:0; overflow-y:auto; padding:12px; display:flex; flex-direction:column; gap:8px; }
|
|
101
|
+
#rm-toolbar-root .rm-panel-footer { display:flex; align-items:center; gap:8px; padding:10px 16px; border-top:1px solid #f3f4f6; font-size:11px; color:#596579; }
|
|
102
|
+
#rm-toolbar-root .rm-status-dot { width:8px; height:8px; border-radius:50%; background:#d1d5db; }
|
|
103
|
+
#rm-toolbar-root .rm-card { padding:12px; background:#fff; border-radius:8px; border:1px solid #e5e7eb; border-left:3px solid; cursor:pointer; transition:all 0.15s; }
|
|
104
|
+
#rm-toolbar-root .rm-card:hover { box-shadow:0 2px 8px rgba(0,0,0,0.05); }
|
|
105
|
+
#rm-toolbar-root .rm-card-top { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
|
|
106
|
+
#rm-toolbar-root .rm-card-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
|
|
107
|
+
#rm-toolbar-root .rm-card-id { font-size:10px; font-weight:600; color:#596579; }
|
|
108
|
+
#rm-toolbar-root .rm-card-badge { padding:2px 6px; font-size:10px; font-weight:500; border-radius:10px; }
|
|
109
|
+
#rm-toolbar-root .rm-card-body { margin-top:6px; font-size:13px; line-height:1.5; color:#1f2937; }
|
|
110
|
+
#rm-toolbar-root .rm-card-path { margin-top:4px; font-size:11px; color:#596579; font-family:monospace; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
111
|
+
#rm-toolbar-root .rm-card-thread { margin-top:8px; padding:8px; background:rgba(249,250,251,0.8); border-radius:8px; font-size:12px; color:#6b7280; border-left:2px solid; }
|
|
112
|
+
#rm-toolbar-root .rm-card-thread-role { font-size:11px; font-weight:600; color:#596579; }
|
|
113
|
+
#rm-toolbar-root .rm-empty { text-align:center; padding:32px 16px; color:#596579; }
|
|
114
|
+
#rm-toolbar-root .rm-empty-icon { font-size:32px; margin-bottom:8px; }
|
|
115
|
+
#rm-toolbar-root .rm-empty-text { font-size:13px; }
|
|
116
|
+
#rm-pins-container .rm-pin { position:absolute; display:flex; align-items:center; justify-content:center; width:20px; height:20px; border-radius:50%; color:#fff; font-size:10px; font-weight:700; cursor:pointer; transition:transform 0.2s; z-index:9979; box-shadow:0 2px 8px rgba(0,0,0,0.2); }
|
|
117
|
+
#rm-pins-container .rm-pin:hover { transform:scale(1.25); }
|
|
118
|
+
#rm-pins-container .rm-pin-active { animation:rm-pulse 2s ease-in-out infinite; }
|
|
119
|
+
#rm-toolbar-root .rm-toast { padding:8px 12px; border-radius:8px; border:1px solid; font-size:12px; font-weight:500; box-shadow:0 2px 8px rgba(0,0,0,0.05); animation:rm-toast-in 0.3s ease; }
|
|
120
|
+
#rm-toolbar-root button, #rm-toolbar-root textarea { font-family:inherit; text-transform:none; letter-spacing:normal; }
|
|
121
|
+
#rm-toolbar-root button:focus-visible { outline:2px solid #6366f1; outline-offset:2px; }
|
|
122
|
+
#rm-toolbar-root .rm-popup-heading { margin:0 0 12px; color:#25272d; font-size:15px; font-weight:650; line-height:1.4; }
|
|
123
|
+
#rm-toolbar-root .rm-popup-el { color:#516074; }
|
|
124
|
+
#rm-toolbar-root #rm-char-count { margin-left:auto; color:#596579; font-size:11px; font-variant-numeric:tabular-nums; }
|
|
125
|
+
#rm-pins-container .rm-pin { font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; }
|
|
126
|
+
#rm-toolbar-root .rm-card-body { overflow-wrap:anywhere; }
|
|
127
|
+
#rm-toolbar-root .rm-popup textarea { line-height:1.6; border-radius:8px; }
|
|
128
|
+
#rm-toolbar-root .rm-empty { color:#596579; line-height:1.6; }
|
|
129
|
+
@media (pointer:coarse) { #rm-toolbar-root .rm-dock button, #rm-toolbar-root .rm-chip, #rm-toolbar-root .rm-menu-btn, #rm-toolbar-root .rm-menu-option, #rm-toolbar-root .rm-panel-close { min-height:44px; min-width:44px; } }
|
|
130
|
+
@media (prefers-reduced-motion:reduce) { #rm-pins-container .rm-pin, #rm-toolbar-root .rm-toast { animation:none; transition:none; } }
|
|
89
131
|
`;
|
|
90
132
|
document.head.appendChild(style);
|
|
91
133
|
},
|
|
@@ -16,43 +16,55 @@
|
|
|
16
16
|
const sizeMap = { "default": { dim: 40, icon: 18 }, compact: { dim: 36, icon: 16 }, slim: { dim: 32, icon: 16 } };
|
|
17
17
|
const fabSize = sizeMap[this.size] || sizeMap["default"];
|
|
18
18
|
|
|
19
|
-
const controlSize = 32;
|
|
20
|
-
const controlGap = 8;
|
|
21
|
-
const controlStart = this.fabVisible ? fabSize.dim + controlGap + 24 : 24;
|
|
22
19
|
const isRight = this.position === "br" || this.position === "tr";
|
|
23
20
|
const isTop = this.position === "tl" || this.position === "tr";
|
|
24
|
-
const settingsToggleStyle = isRight ? `${isTop ? 'top' : 'bottom'}:24px;right:${controlStart}px;` : `${isTop ? 'top' : 'bottom'}:24px;left:${controlStart}px;`;
|
|
25
|
-
const panelToggleStyle = isRight ? `${isTop ? 'top' : 'bottom'}:24px;right:${controlStart + controlSize + controlGap}px;` : `${isTop ? 'top' : 'bottom'}:24px;left:${controlStart + controlSize + controlGap}px;`;
|
|
26
21
|
const panelStyle = isRight
|
|
27
|
-
? `${isTop ? 'top' : 'bottom'}:${fabSize.dim +
|
|
28
|
-
: `${isTop ? 'top' : 'bottom'}:${fabSize.dim +
|
|
22
|
+
? `${isTop ? 'top' : 'bottom'}:${fabSize.dim + 42}px;right:24px;`
|
|
23
|
+
: `${isTop ? 'top' : 'bottom'}:${fabSize.dim + 42}px;left:24px;`;
|
|
29
24
|
const toastStyle = isRight
|
|
30
|
-
? `${isTop ? 'top' : 'bottom'}:${fabSize.dim +
|
|
31
|
-
: `${isTop ? 'top' : 'bottom'}:${fabSize.dim +
|
|
25
|
+
? `${isTop ? 'top' : 'bottom'}:${fabSize.dim + 42}px;right:24px;`
|
|
26
|
+
: `${isTop ? 'top' : 'bottom'}:${fabSize.dim + 42}px;left:24px;`;
|
|
32
27
|
|
|
33
28
|
root.innerHTML = `
|
|
34
|
-
<
|
|
35
|
-
|
|
29
|
+
<div class="rm-dock" id="rm-dock" role="group" aria-label="Markup tools" style="${fabPos}--rm-accent:${accentBg};--rm-accent-hover:${accentBgHover};--rm-control-size:${fabSize.dim}px">
|
|
30
|
+
<button type="button" class="rm-fab" id="rm-fab" style="width:${fabSize.dim}px;height:${fabSize.dim}px;${this.fabVisible ? "" : "display:none;"}" title="Expand markup tools" aria-label="Expand markup tools" aria-expanded="false" aria-controls="rm-dock-controls" aria-pressed="false">
|
|
31
|
+
<svg viewBox="0 0 24 24" style="width:${fabSize.icon}px;height:${fabSize.icon}px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;"><path d="M16 3l5 5M4 15L16 3l5 5L9 20l-6 1 1-6z"/></svg>
|
|
36
32
|
</button>
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
</button>
|
|
40
|
-
<button class="rm-panel-toggle" id="rm-panel-toggle" style="${panelToggleStyle}" title="View annotations" aria-label="View annotations" aria-controls="rm-panel">
|
|
33
|
+
<div id="rm-dock-controls" class="rm-dock-controls" hidden>
|
|
34
|
+
<button type="button" class="rm-panel-toggle" id="rm-panel-toggle" aria-expanded="false" title="View annotations" aria-label="View annotations" aria-controls="rm-panel">
|
|
41
35
|
<svg viewBox="0 0 24 24"><path d="M4 6h16M4 12h16M4 18h7"/></svg>
|
|
42
36
|
<span class="rm-panel-toggle-badge" id="rm-panel-toggle-badge"></span>
|
|
43
37
|
</button>
|
|
38
|
+
<button type="button" class="rm-toolbar-settings" id="rm-settings-toggle" title="Toolbar settings" aria-label="Toolbar settings" aria-expanded="false" aria-controls="rm-settings-panel">
|
|
39
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9 3h6l1 3 3 1 2 5-2 5-3 1-1 3H9l-1-3-3-1-2-5 2-5 3-1 1-3z"/><circle cx="12" cy="12" r="3"/></svg>
|
|
40
|
+
</button>
|
|
41
|
+
<button type="button" class="rm-dock-close" id="rm-dock-close" title="Collapse markup tools" aria-label="Collapse markup tools"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6L6 18"/></svg></button>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
44
|
<div class="rm-toast-container" id="rm-toast-container" style="${toastStyle}"></div>
|
|
45
45
|
<div class="rm-popup" id="rm-popup" role="dialog" aria-label="Add annotation" aria-modal="false">
|
|
46
|
+
<h3 class="rm-popup-heading">Leave feedback</h3>
|
|
46
47
|
<div style="margin-bottom:12px">
|
|
47
48
|
<p class="rm-popup-el" id="rm-popup-el"></p>
|
|
48
49
|
<p class="rm-popup-text" id="rm-popup-text"></p>
|
|
49
50
|
</div>
|
|
50
|
-
<
|
|
51
|
-
<div
|
|
51
|
+
<details class="rm-image-options" id="rm-image-options" ${this.enableScreenshots ? "" : "hidden"}><summary>Attach image</summary>
|
|
52
|
+
<div id="rm-screenshot-actions" class="rm-screenshot-actions">
|
|
53
|
+
<button type="button" id="rm-attach-screen">Capture tab</button>
|
|
54
|
+
<button type="button" id="rm-attach-file">Upload image</button>
|
|
55
|
+
<button type="button" id="rm-remove-screenshot" hidden>Remove image</button>
|
|
56
|
+
<input type="file" id="rm-screenshot-file" accept="image/png,image/jpeg,image/webp" hidden>
|
|
57
|
+
<span id="rm-screenshot-status" role="status">Optional · capture, upload, or paste an image</span>
|
|
58
|
+
</div>
|
|
59
|
+
</details>
|
|
60
|
+
<textarea id="rm-popup-input" rows="3" placeholder="What should change?" aria-label="What should change?"></textarea>
|
|
61
|
+
<details class="rm-image-options"><summary>Type & priority</summary>
|
|
62
|
+
<div style="display:flex;align-items:center;gap:8px;margin-top:8px">
|
|
52
63
|
${this._menuMarkup({ inputId: "rm-intent-select", label: "Intent", value: "change", options: this._intentOptions() })}
|
|
53
64
|
${this._menuMarkup({ inputId: "rm-severity-select", label: "Severity", value: "suggestion", options: this._severityOptions() })}
|
|
54
65
|
<span class="rm-count" id="rm-char-count"></span>
|
|
55
66
|
</div>
|
|
67
|
+
</details>
|
|
56
68
|
<div class="rm-popup-actions">
|
|
57
69
|
<button class="rm-btn-cancel" id="rm-btn-cancel">Cancel</button>
|
|
58
70
|
<button class="rm-btn-submit" id="rm-btn-submit" style="background:${accentBg}">
|
|
@@ -91,6 +103,8 @@
|
|
|
91
103
|
|
|
92
104
|
document.body.appendChild(root);
|
|
93
105
|
this.root = root;
|
|
106
|
+
this.dockState = this.fabVisible ? "collapsed" : "expanded";
|
|
107
|
+
this._renderDockState();
|
|
94
108
|
// Pins container lives on body (not inside fixed root); scroll listener keeps them stuck to target elements
|
|
95
109
|
const pinsContainer = document.createElement("div");
|
|
96
110
|
pinsContainer.className = "rm-pins-container";
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
Object.assign(RailsMarkupToolbar, {
|
|
2
2
|
_bindEvents() {
|
|
3
3
|
const self = this;
|
|
4
|
-
document.getElementById("rm-
|
|
4
|
+
document.getElementById("rm-attach-screen").addEventListener("click", () => self._attachScreen());
|
|
5
|
+
document.getElementById("rm-attach-file").addEventListener("click", () => document.getElementById("rm-screenshot-file").click());
|
|
6
|
+
document.getElementById("rm-screenshot-file").addEventListener("change", e => self._attachScreenshotFile(e.target.files[0]));
|
|
7
|
+
document.getElementById("rm-remove-screenshot").addEventListener("click", () => self._removeScreenshot());
|
|
8
|
+
document.getElementById("rm-popup-input").addEventListener("paste", e => {
|
|
9
|
+
if (!self.enableScreenshots) return;
|
|
10
|
+
const file = Array.from(e.clipboardData?.items || []).find(item => item.type.startsWith("image/"))?.getAsFile();
|
|
11
|
+
if (file) { e.preventDefault(); self._attachScreenshotFile(file); }
|
|
12
|
+
});
|
|
13
|
+
document.getElementById("rm-fab").addEventListener("click", () => self.dockState === "collapsed" ? self._expandDock() : self.toggleMode());
|
|
14
|
+
document.getElementById("rm-dock-close").addEventListener("click", () => self.active ? self._deactivateMode() : self._collapseDock());
|
|
5
15
|
document.getElementById("rm-panel-toggle").addEventListener("click", () => self.togglePanel());
|
|
6
|
-
document.getElementById("rm-panel-close").addEventListener("click", () => self.togglePanel());
|
|
16
|
+
document.getElementById("rm-panel-close").addEventListener("click", () => self._settingsPanelOpen ? self._toggleSettings() : self.togglePanel());
|
|
7
17
|
document.getElementById("rm-settings-toggle").addEventListener("click", () => self._toggleSettings());
|
|
8
18
|
document.getElementById("rm-btn-cancel").addEventListener("click", () => self._closePopup());
|
|
9
19
|
document.getElementById("rm-btn-submit").addEventListener("click", (e) => self.submitAnnotation(e));
|
|
@@ -136,6 +146,8 @@
|
|
|
136
146
|
const panel = document.getElementById("rm-panel");
|
|
137
147
|
if (panel) panel.style.display = "none";
|
|
138
148
|
|
|
149
|
+
document.getElementById("rm-panel-toggle")?.setAttribute("aria-expanded", "false");
|
|
150
|
+
|
|
139
151
|
// Rerender pins for current page (annotations are global, pins are page-specific)
|
|
140
152
|
this._renderPins();
|
|
141
153
|
this._updateCount();
|
|
@@ -161,11 +173,9 @@
|
|
|
161
173
|
},
|
|
162
174
|
_activateMode() {
|
|
163
175
|
document.body.style.cursor = "crosshair";
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
fab.style.boxShadow = `0 0 0 3px ${this._accentBg()}, 0 0 0 6px rgba(99,102,241,0.2)`;
|
|
168
|
-
fab.innerHTML = `<svg viewBox="0 0 24 24" style="width:${iconSize}px;height:${iconSize}px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round"><path d="M6 18L18 6M6 6l12 12"/></svg>`;
|
|
176
|
+
this.active = true;
|
|
177
|
+
this.dockState = "annotating";
|
|
178
|
+
this._renderDockState();
|
|
169
179
|
document.addEventListener("mousemove", this._boundMouseMove, true);
|
|
170
180
|
document.addEventListener("mousedown", this._boundMouseDown, true);
|
|
171
181
|
document.addEventListener("mouseup", this._boundMouseUp, true);
|
|
@@ -176,14 +186,8 @@
|
|
|
176
186
|
_deactivateMode() {
|
|
177
187
|
this.active = false;
|
|
178
188
|
document.body.style.cursor = "";
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const iconSize = this._fabIconSize();
|
|
182
|
-
fab.style.transform = "";
|
|
183
|
-
fab.style.boxShadow = "0 4px 12px rgba(0,0,0,0.15)";
|
|
184
|
-
fab.innerHTML = `<svg viewBox="0 0 24 24" style="width:${iconSize}px;height:${iconSize}px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>`;
|
|
185
|
-
this._updateCount();
|
|
186
|
-
}
|
|
189
|
+
if (this.dockState === "annotating") this.dockState = "expanded";
|
|
190
|
+
this._renderDockState();
|
|
187
191
|
document.removeEventListener("mousemove", this._boundMouseMove, true);
|
|
188
192
|
document.removeEventListener("mousedown", this._boundMouseDown, true);
|
|
189
193
|
document.removeEventListener("mouseup", this._boundMouseUp, true);
|
|
@@ -192,16 +196,53 @@
|
|
|
192
196
|
document.removeEventListener("touchend", this._boundTouchEnd, true);
|
|
193
197
|
this._removeHighlight();
|
|
194
198
|
},
|
|
199
|
+
_renderDockState() {
|
|
200
|
+
const dock = document.getElementById("rm-dock");
|
|
201
|
+
if (!dock) return;
|
|
202
|
+
dock.style.display = this.fabVisible ? "flex" : "none";
|
|
203
|
+
const expanded = this.dockState !== "collapsed";
|
|
204
|
+
dock.dataset.state = this.dockState;
|
|
205
|
+
document.getElementById("rm-dock-controls").hidden = !expanded;
|
|
206
|
+
const fab = document.getElementById("rm-fab");
|
|
207
|
+
const label = !expanded ? "Expand markup tools" : this.active ? "Stop annotating" : "Annotate an element";
|
|
208
|
+
fab.title = label;
|
|
209
|
+
fab.setAttribute("aria-label", label);
|
|
210
|
+
fab.setAttribute("aria-expanded", String(expanded));
|
|
211
|
+
fab.setAttribute("aria-pressed", String(this.active));
|
|
212
|
+
const close = document.getElementById("rm-dock-close");
|
|
213
|
+
close.hidden = !this.fabVisible && !this.active;
|
|
214
|
+
close.style.display = close.hidden ? "none" : "flex";
|
|
215
|
+
close.title = this.active ? "Stop annotating" : "Collapse markup tools";
|
|
216
|
+
close.setAttribute("aria-label", close.title);
|
|
217
|
+
},
|
|
218
|
+
_expandDock() {
|
|
219
|
+
if (!this.active) this.dockState = "expanded";
|
|
220
|
+
this._renderDockState();
|
|
221
|
+
},
|
|
222
|
+
_collapseDock() {
|
|
223
|
+
this._deactivateMode();
|
|
224
|
+
this._closePopup();
|
|
225
|
+
this._closeAllMenus();
|
|
226
|
+
document.getElementById("rm-panel").style.display = "none";
|
|
227
|
+
document.getElementById("rm-panel-toggle").setAttribute("aria-expanded", "false");
|
|
228
|
+
document.getElementById("rm-settings-panel").hidden = true;
|
|
229
|
+
document.getElementById("rm-settings-toggle").setAttribute("aria-expanded", "false");
|
|
230
|
+
this._settingsPanelOpen = false;
|
|
231
|
+
this.dockState = this.fabVisible ? "collapsed" : "expanded";
|
|
232
|
+
this._renderDockState();
|
|
233
|
+
if (this.fabVisible) document.getElementById("rm-fab").focus();
|
|
234
|
+
},
|
|
195
235
|
togglePanel() {
|
|
236
|
+
this._expandDock();
|
|
196
237
|
const panel = document.getElementById("rm-panel");
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
238
|
+
const opening = panel.style.display !== "flex" || panel.dataset.view === "settings";
|
|
239
|
+
panel.dataset.view = "feedback";
|
|
240
|
+
panel.querySelector("h3").textContent = "Feedback";
|
|
241
|
+
document.getElementById("rm-settings-panel").hidden = true;
|
|
242
|
+
document.getElementById("rm-settings-toggle").setAttribute("aria-expanded", "false");
|
|
243
|
+
this._settingsPanelOpen = false;
|
|
244
|
+
panel.style.display = opening ? "flex" : "none";
|
|
245
|
+
document.getElementById("rm-panel-toggle").setAttribute("aria-expanded", String(opening));
|
|
205
246
|
},
|
|
206
247
|
_handleMouseMove(event) {
|
|
207
248
|
if (!this.active) return;
|
|
@@ -235,9 +276,7 @@
|
|
|
235
276
|
this.selectedText = (sel && sel.toString().trim().length > 0) ? sel.toString().trim() : null;
|
|
236
277
|
this._currentElement = this._identify(el);
|
|
237
278
|
this._currentScreenshot = null;
|
|
238
|
-
|
|
239
|
-
this._currentScreenshot = await this._captureElement(el);
|
|
240
|
-
}
|
|
279
|
+
|
|
241
280
|
this._showPopup(event.clientX, event.clientY);
|
|
242
281
|
this.clickedElement = null;
|
|
243
282
|
},
|
|
@@ -315,6 +354,12 @@
|
|
|
315
354
|
return;
|
|
316
355
|
}
|
|
317
356
|
}
|
|
357
|
+
if (event.key === "Escape" && this.dockState === "expanded") {
|
|
358
|
+
this._collapseDock();
|
|
359
|
+
event.preventDefault();
|
|
360
|
+
event.stopPropagation();
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
318
363
|
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
319
364
|
const popup = document.getElementById("rm-popup");
|
|
320
365
|
if (popup && popup.style.display === "block") {
|
|
@@ -112,8 +112,8 @@
|
|
|
112
112
|
this._updateCount();
|
|
113
113
|
const panel = document.getElementById("rm-panel");
|
|
114
114
|
if (panel) panel.style.display = "flex";
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
this._expandDock();
|
|
116
|
+
document.getElementById("rm-panel-toggle")?.setAttribute("aria-expanded", "true");
|
|
117
117
|
return false;
|
|
118
118
|
},
|
|
119
119
|
_localStateSnapshot() {
|