rails-markup 1.4.5 → 1.4.6
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/app/assets/javascripts/rails_markup/toolbar/00-core.js +3 -0
- data/app/assets/javascripts/rails_markup/toolbar/10-styles.js +11 -1
- data/app/assets/javascripts/rails_markup/toolbar/20-dom.js +19 -8
- data/app/assets/javascripts/rails_markup/toolbar/40-events.js +10 -6
- data/app/assets/javascripts/rails_markup/toolbar/50-sync.js +36 -1
- data/app/assets/javascripts/rails_markup/toolbar/60-render.js +114 -1
- data/app/assets/javascripts/rails_markup/toolbar/90-init.js +15 -5
- data/app/views/layouts/rails_markup/application.html.erb +1 -0
- data/app/views/rails_markup/dashboard/show.html.erb +1 -1
- data/lib/generators/rails_markup/install/templates/initializer.rb.erb +1 -1
- data/lib/rails_markup/cli/setup_wizard.rb +1 -1
- data/lib/rails_markup/configuration.rb +1 -1
- data/lib/rails_markup/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 71cb0dfae1e50403d787bb64d3760a95181fbf2e4fbd7ce6c57629d226fd2dae
|
|
4
|
+
data.tar.gz: ba57fa0fde60fd7b8c314ad63d8b2df16c3580076269392991928e81e3a6d53a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7bb524122341ef07f5ea882964f931e4bb766e4c493a7fb0493f0a0c1ca7fb793055ad513219df8f13bafc578b2ea5113bba0fe86f3b51eabaa15b4e12b36cb5
|
|
7
|
+
data.tar.gz: 7f2f47ab1f1692dcb9ff5127b7691dd5ca2691a1a2944056d6e65bc9f2cf5dd998c2e58554722f23b80df36e64aa486f94b5f746b60e4a95d01e1a3f93898e16
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
activeFilter: "all",
|
|
28
28
|
editingId: null,
|
|
29
29
|
_currentScreenshot: null,
|
|
30
|
+
toolbarSettings: {},
|
|
30
31
|
_storageError: null,
|
|
31
32
|
_outboxFlushScheduled: false,
|
|
32
33
|
_outboxFlushTimer: null,
|
|
@@ -44,6 +45,8 @@
|
|
|
44
45
|
_syncMalformedLimit: 3,
|
|
45
46
|
_syncUnavailable: null,
|
|
46
47
|
legacyStorageEndpoint: null,
|
|
48
|
+
_bootstrapOptions: null,
|
|
49
|
+
_settingsPanelOpen: false,
|
|
47
50
|
|
|
48
51
|
// Drawing state
|
|
49
52
|
drawingMode: null, // null | "arrow" | "rect" | "highlight"
|
|
@@ -9,13 +9,17 @@
|
|
|
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
|
-
.rm-fab, .rm-panel-toggle, .rm-panel, .rm-popup { pointer-events:auto; }
|
|
12
|
+
.rm-fab, .rm-panel-toggle, .rm-toolbar-settings, .rm-panel, .rm-popup { pointer-events:auto; }
|
|
13
13
|
.rm-fab { position:fixed; z-index:9980; border-radius:50%; border:none; cursor:pointer; display:flex; align-items:center; justify-content:center; transition:all 0.2s; box-shadow:0 4px 12px rgba(0,0,0,0.15); }
|
|
14
14
|
.rm-fab svg { width:20px; height:20px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
|
|
15
15
|
.rm-fab-badge { position:absolute; top:-4px; right:-4px; min-width:20px; height:20px; padding:0 4px; border-radius:10px; background:#ef4444; color:#fff; font-size:11px; font-weight:700; display:none; align-items:center; justify-content:center; }
|
|
16
16
|
.rm-panel-toggle { position:fixed; z-index:9980; width:32px; height:32px; border-radius:50%; border:1px solid #e5e7eb; background:rgba(255,255,255,0.9); cursor:pointer; display:none; align-items:center; justify-content:center; color:#6b7280; transition:all 0.2s; backdrop-filter:blur(8px); }
|
|
17
17
|
.rm-panel-toggle:hover { color:#4361ee; }
|
|
18
18
|
.rm-panel-toggle svg { width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
|
|
19
|
+
.rm-panel-toggle-badge { position:absolute; top:-4px; right:-4px; min-width:18px; height:18px; padding:0 4px; border-radius:9px; background:#ef4444; color:#fff; font-size:10px; font-weight:700; display:none; align-items:center; justify-content:center; }
|
|
20
|
+
.rm-toolbar-settings { position:fixed; z-index:9980; width:32px; height:32px; border-radius:50%; border:1px solid #e5e7eb; background:#fff; cursor:pointer; display:none; align-items:center; justify-content:center; color:#6b7280; transition:all 0.2s; backdrop-filter:blur(8px); }
|
|
21
|
+
.rm-toolbar-settings:hover { color:#374151; background:#f9fafb; }
|
|
22
|
+
.rm-toolbar-settings svg { width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
|
|
19
23
|
.rm-toast-container { position:fixed; z-index:9983; display:flex; flex-direction:column; gap:8px; pointer-events:none; }
|
|
20
24
|
.rm-pins-container { position:absolute; top:0; left:0; width:100%; z-index:9979; pointer-events:none; }
|
|
21
25
|
.rm-pin { pointer-events:auto; }
|
|
@@ -47,7 +51,13 @@
|
|
|
47
51
|
.rm-panel { display:none; position:fixed; z-index:9981; width:380px; max-width:calc(100vw - 48px); max-height:60vh; background:rgba(255,255,255,0.95); backdrop-filter:blur(12px); border-radius:16px; box-shadow:0 25px 50px rgba(0,0,0,0.1); border:1px solid rgba(229,231,235,0.8); flex-direction:column; }
|
|
48
52
|
.rm-panel-header { display:flex; align-items:center; justify-content:space-between; padding:12px 16px; border-bottom:1px solid #f3f4f6; }
|
|
49
53
|
.rm-panel-header h3 { font-size:14px; font-weight:600; color:#1f2937; }
|
|
54
|
+
.rm-panel-header-actions { display:flex; align-items:center; gap:6px; }
|
|
50
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:12px 16px 4px; border-bottom:1px solid #f3f4f6; }
|
|
57
|
+
.rm-settings[hidden] { display:none; }
|
|
58
|
+
.rm-settings-group { display:flex; flex-direction:column; gap:6px; margin-bottom:10px; }
|
|
59
|
+
.rm-settings-label { font-size:11px; font-weight:600; color:#6b7280; text-transform:uppercase; letter-spacing:0.05em; }
|
|
60
|
+
.rm-settings-options { display:flex; flex-wrap:wrap; gap:6px; }
|
|
51
61
|
.rm-panel-close { padding:6px; color:#d1d5db; background:none; border:none; cursor:pointer; border-radius:8px; }
|
|
52
62
|
.rm-panel-close:hover { color:#6b7280; }
|
|
53
63
|
.rm-panel-close svg { width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
|
|
@@ -12,14 +12,17 @@
|
|
|
12
12
|
const posMap = { bl: "bottom:24px;left:24px;", br: "bottom:24px;right:24px;", tl: "top:24px;left:24px;", tr: "top:24px;right:24px;" };
|
|
13
13
|
const fabPos = posMap[this.position] || posMap.bl;
|
|
14
14
|
|
|
15
|
-
// Size: default (
|
|
16
|
-
const sizeMap = { "default": { dim:
|
|
15
|
+
// Size: default (40px), compact (36px), slim (32px)
|
|
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
|
-
|
|
19
|
+
const controlSize = 32;
|
|
20
|
+
const controlGap = 8;
|
|
21
|
+
const controlStart = this.fabVisible ? fabSize.dim + controlGap + 24 : 24;
|
|
20
22
|
const isRight = this.position === "br" || this.position === "tr";
|
|
21
23
|
const isTop = this.position === "tl" || this.position === "tr";
|
|
22
|
-
const
|
|
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;`;
|
|
23
26
|
const panelStyle = isRight
|
|
24
27
|
? `${isTop ? 'top' : 'bottom'}:${fabSize.dim + 32}px;right:24px;`
|
|
25
28
|
: `${isTop ? 'top' : 'bottom'}:${fabSize.dim + 32}px;left:24px;`;
|
|
@@ -30,10 +33,13 @@
|
|
|
30
33
|
root.innerHTML = `
|
|
31
34
|
<button class="rm-fab" id="rm-fab" style="${fabPos}width:${fabSize.dim}px;height:${fabSize.dim}px;background:${accentBg};color:#fff;${this.fabVisible ? "" : "display:none;"}" title="Toggle annotation mode" aria-label="Toggle annotation mode" aria-expanded="false" aria-controls="rm-panel">
|
|
32
35
|
<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="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>
|
|
33
|
-
|
|
36
|
+
</button>
|
|
37
|
+
<button class="rm-toolbar-settings" id="rm-settings-toggle" style="${settingsToggleStyle}" title="Toolbar settings" aria-label="Toolbar settings" aria-expanded="false" aria-controls="rm-settings-panel">
|
|
38
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 8a4 4 0 100 8 4 4 0 000-8zm8.94 3.06l-1.3-.75.08-1.36a1 1 0 00-.3-.79l-1.72-1.72a1 1 0 00-.79-.3l-1.36.08-.75-1.3a1 1 0 00-.86-.5h-2.44a1 1 0 00-.86.5l-.75 1.3-1.36-.08a1 1 0 00-.79.3L4.58 8.86a1 1 0 00-.3.79l.08 1.36-1.3.75a1 1 0 00-.5.86v2.44a1 1 0 00.5.86l1.3.75-.08 1.36a1 1 0 00.3.79l1.72 1.72a1 1 0 00.79.3l1.36-.08.75 1.3a1 1 0 00.86.5h2.44a1 1 0 00.86-.5l.75-1.3 1.36.08a1 1 0 00.79-.3l1.72-1.72a1 1 0 00.3-.79l-.08-1.36 1.3-.75a1 1 0 00.5-.86v-2.44a1 1 0 00-.5-.86zm-2.24 1.44l-1.14.66a1 1 0 00-.5.86l.08 1.2-.98.98-1.2-.08a1 1 0 00-.86.5l-.66 1.14h-1.96l-.66-1.14a1 1 0 00-.86-.5l-1.2.08-.98-.98.08-1.2a1 1 0 00-.5-.86l-1.14-.66v-1.96l1.14-.66a1 1 0 00.5-.86l-.08-1.2.98-.98 1.2.08a1 1 0 00.86-.5l.66-1.14h1.96l.66 1.14a1 1 0 00.86.5l1.2-.08.98.98-.08 1.2a1 1 0 00.5.86l1.14.66v1.96z"/></svg>
|
|
34
39
|
</button>
|
|
35
40
|
<button class="rm-panel-toggle" id="rm-panel-toggle" style="${panelToggleStyle}" title="View annotations" aria-label="View annotations" aria-controls="rm-panel">
|
|
36
41
|
<svg viewBox="0 0 24 24"><path d="M4 6h16M4 12h16M4 18h7"/></svg>
|
|
42
|
+
<span class="rm-panel-toggle-badge" id="rm-panel-toggle-badge"></span>
|
|
37
43
|
</button>
|
|
38
44
|
<div class="rm-toast-container" id="rm-toast-container" style="${toastStyle}"></div>
|
|
39
45
|
<div class="rm-popup" id="rm-popup" role="dialog" aria-label="Add annotation" aria-modal="false">
|
|
@@ -61,9 +67,14 @@
|
|
|
61
67
|
<h3>Feedback</h3>
|
|
62
68
|
<span class="rm-panel-count" id="rm-panel-count" style="background:${accentLight};color:${accentText}">0</span>
|
|
63
69
|
</div>
|
|
64
|
-
<
|
|
65
|
-
<
|
|
66
|
-
|
|
70
|
+
<div class="rm-panel-header-actions">
|
|
71
|
+
<button class="rm-panel-close" id="rm-panel-close" aria-label="Close annotations panel">
|
|
72
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 18L18 6M6 6l12 12"/></svg>
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
<div class="rm-settings" id="rm-settings-panel" hidden>
|
|
77
|
+
${this._toolbarSettingsMarkup()}
|
|
67
78
|
</div>
|
|
68
79
|
<div class="rm-filter-chips" id="rm-filter-chips">
|
|
69
80
|
<button class="rm-chip rm-chip-active" data-filter="all" style="background:${accentBg}">All</button>
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
document.getElementById("rm-fab").addEventListener("click", () => self.toggleMode());
|
|
5
5
|
document.getElementById("rm-panel-toggle").addEventListener("click", () => self.togglePanel());
|
|
6
6
|
document.getElementById("rm-panel-close").addEventListener("click", () => self.togglePanel());
|
|
7
|
+
document.getElementById("rm-settings-toggle").addEventListener("click", () => self._toggleSettings());
|
|
7
8
|
document.getElementById("rm-btn-cancel").addEventListener("click", () => self._closePopup());
|
|
8
9
|
document.getElementById("rm-btn-submit").addEventListener("click", (e) => self.submitAnnotation(e));
|
|
9
10
|
document.getElementById("rm-popup-input").addEventListener("input", () => self._updateCharCount());
|
|
@@ -15,6 +16,13 @@
|
|
|
15
16
|
// Custom menus (intent/severity/status) — button+menu, never native selects
|
|
16
17
|
// so host FormSelect/Select2 enhancers cannot rewrite our DOM (#4).
|
|
17
18
|
this.root.addEventListener("click", (e) => {
|
|
19
|
+
const setting = e.target.closest("[data-setting]");
|
|
20
|
+
if (setting) {
|
|
21
|
+
e.preventDefault();
|
|
22
|
+
e.stopPropagation();
|
|
23
|
+
this._setToolbarSetting(setting.dataset.setting, setting.dataset.value);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
18
26
|
const option = e.target.closest(".rm-menu-option");
|
|
19
27
|
if (option) {
|
|
20
28
|
e.preventDefault();
|
|
@@ -147,10 +155,6 @@
|
|
|
147
155
|
this.active = !this.active;
|
|
148
156
|
if (this.active) {
|
|
149
157
|
this._activateMode();
|
|
150
|
-
// Always open panel when activating annotation mode
|
|
151
|
-
if (document.getElementById("rm-panel").style.display !== "flex") {
|
|
152
|
-
this.togglePanel();
|
|
153
|
-
}
|
|
154
158
|
} else {
|
|
155
159
|
this._deactivateMode();
|
|
156
160
|
}
|
|
@@ -161,7 +165,7 @@
|
|
|
161
165
|
const iconSize = this._fabIconSize();
|
|
162
166
|
fab.style.transform = "scale(0.9)";
|
|
163
167
|
fab.style.boxShadow = `0 0 0 3px ${this._accentBg()}, 0 0 0 6px rgba(99,102,241,0.2)`;
|
|
164
|
-
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
|
|
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>`;
|
|
165
169
|
document.addEventListener("mousemove", this._boundMouseMove, true);
|
|
166
170
|
document.addEventListener("mousedown", this._boundMouseDown, true);
|
|
167
171
|
document.addEventListener("mouseup", this._boundMouseUp, true);
|
|
@@ -177,7 +181,7 @@
|
|
|
177
181
|
const iconSize = this._fabIconSize();
|
|
178
182
|
fab.style.transform = "";
|
|
179
183
|
fab.style.boxShadow = "0 4px 12px rgba(0,0,0,0.15)";
|
|
180
|
-
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
|
|
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>`;
|
|
181
185
|
this._updateCount();
|
|
182
186
|
}
|
|
183
187
|
document.removeEventListener("mousemove", this._boundMouseMove, true);
|
|
@@ -3,8 +3,41 @@
|
|
|
3
3
|
const endpoint = (this.endpoint || "/feedback/api").replace(/\/+$/, "") || "/";
|
|
4
4
|
return `rm-annotations:${encodeURIComponent(endpoint)}`;
|
|
5
5
|
},
|
|
6
|
+
_toolbarSettingsKey() {
|
|
7
|
+
const endpoint = (this.endpoint || "/feedback/api").replace(/\/+$/, "") || "/";
|
|
8
|
+
return `rm-toolbar-settings:${encodeURIComponent(endpoint)}`;
|
|
9
|
+
},
|
|
6
10
|
_pageUrl() { return window.location.pathname + window.location.search; },
|
|
7
11
|
_pageStorageKey() { return this._storageKey() + ":" + this._pageUrl(); },
|
|
12
|
+
_normalizeToolbarSettings(candidate = {}) {
|
|
13
|
+
const source = candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : {};
|
|
14
|
+
const normalized = {};
|
|
15
|
+
if (this._validToolbarAccent(source.accent)) normalized.accent = source.accent;
|
|
16
|
+
if (this._validToolbarPosition(source.position)) normalized.position = source.position;
|
|
17
|
+
if (this._validToolbarSize(source.size)) normalized.size = source.size;
|
|
18
|
+
if (typeof source.fabVisible === "boolean") normalized.fabVisible = source.fabVisible;
|
|
19
|
+
if (typeof source.enableScreenshots === "boolean") normalized.enableScreenshots = source.enableScreenshots;
|
|
20
|
+
return normalized;
|
|
21
|
+
},
|
|
22
|
+
_loadToolbarSettings() {
|
|
23
|
+
try {
|
|
24
|
+
const raw = localStorage.getItem(this._toolbarSettingsKey());
|
|
25
|
+
if (!raw) return {};
|
|
26
|
+
return this._normalizeToolbarSettings(JSON.parse(raw));
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.warn("[rails-markup] settings load failed:", e);
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
_saveToolbarSettings(settings = this.toolbarSettings || {}) {
|
|
33
|
+
try {
|
|
34
|
+
localStorage.setItem(this._toolbarSettingsKey(), JSON.stringify(this._normalizeToolbarSettings(settings)));
|
|
35
|
+
return true;
|
|
36
|
+
} catch (e) {
|
|
37
|
+
console.warn("[rails-markup] settings save failed:", e);
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
},
|
|
8
41
|
_saveToStorage() {
|
|
9
42
|
try {
|
|
10
43
|
// Cross-tab storage-event merging is deferred: safely reconciling ordered
|
|
@@ -72,6 +105,7 @@
|
|
|
72
105
|
this.outbox = snapshot.outbox;
|
|
73
106
|
this.nextId = snapshot.nextId;
|
|
74
107
|
this.legacyMigrations = snapshot.legacyMigrations;
|
|
108
|
+
this.toolbarSettings = snapshot.toolbarSettings || {};
|
|
75
109
|
this._storageError = "Changes could not be saved in this browser. Free storage space and try again.";
|
|
76
110
|
this._renderPins();
|
|
77
111
|
this._rebuildList();
|
|
@@ -87,7 +121,8 @@
|
|
|
87
121
|
annotations: this.annotations,
|
|
88
122
|
outbox: this.outbox,
|
|
89
123
|
nextId: this.nextId,
|
|
90
|
-
legacyMigrations: this.legacyMigrations
|
|
124
|
+
legacyMigrations: this.legacyMigrations,
|
|
125
|
+
toolbarSettings: this.toolbarSettings
|
|
91
126
|
}));
|
|
92
127
|
},
|
|
93
128
|
_mergeDirtyFields(...collections) {
|
|
@@ -329,7 +329,7 @@
|
|
|
329
329
|
const count = this.annotations.length;
|
|
330
330
|
const countEl = document.getElementById("rm-panel-count");
|
|
331
331
|
if (countEl) countEl.textContent = count;
|
|
332
|
-
const badge = document.getElementById("rm-
|
|
332
|
+
const badge = document.getElementById("rm-panel-toggle-badge");
|
|
333
333
|
if (badge) {
|
|
334
334
|
if (count > 0) { badge.textContent = count; badge.style.display = "flex"; }
|
|
335
335
|
else { badge.style.display = "none"; }
|
|
@@ -419,6 +419,119 @@
|
|
|
419
419
|
}
|
|
420
420
|
if (text) text.textContent = this.serverOnline ? "Connected" : (this._syncUnavailable || "Offline");
|
|
421
421
|
},
|
|
422
|
+
_validToolbarAccent(value) {
|
|
423
|
+
return ["indigo", "amber", "blue", "emerald", "rose"].includes(value);
|
|
424
|
+
},
|
|
425
|
+
_validToolbarPosition(value) {
|
|
426
|
+
return ["bl", "br", "tl", "tr"].includes(value);
|
|
427
|
+
},
|
|
428
|
+
_validToolbarSize(value) {
|
|
429
|
+
return ["slim", "compact", "default"].includes(value);
|
|
430
|
+
},
|
|
431
|
+
_toolbarSettingOptions(setting) {
|
|
432
|
+
switch (setting) {
|
|
433
|
+
case "accent":
|
|
434
|
+
return [
|
|
435
|
+
["indigo", "Indigo"],
|
|
436
|
+
["amber", "Amber"],
|
|
437
|
+
["blue", "Blue"],
|
|
438
|
+
["emerald", "Emerald"],
|
|
439
|
+
["rose", "Rose"]
|
|
440
|
+
];
|
|
441
|
+
case "position":
|
|
442
|
+
return [
|
|
443
|
+
["bl", "Bottom-left"],
|
|
444
|
+
["br", "Bottom-right"],
|
|
445
|
+
["tl", "Top-left"],
|
|
446
|
+
["tr", "Top-right"]
|
|
447
|
+
];
|
|
448
|
+
case "size":
|
|
449
|
+
return [
|
|
450
|
+
["default", "Default"],
|
|
451
|
+
["compact", "Compact"],
|
|
452
|
+
["slim", "Slim"]
|
|
453
|
+
];
|
|
454
|
+
case "fabVisible":
|
|
455
|
+
case "enableScreenshots":
|
|
456
|
+
return [
|
|
457
|
+
[true, "On"],
|
|
458
|
+
[false, "Off"]
|
|
459
|
+
];
|
|
460
|
+
default:
|
|
461
|
+
return [];
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
_toolbarSettingLabel(setting) {
|
|
465
|
+
switch (setting) {
|
|
466
|
+
case "accent": return "Accent";
|
|
467
|
+
case "position": return "Position";
|
|
468
|
+
case "size": return "Size";
|
|
469
|
+
case "fabVisible": return "Show FAB";
|
|
470
|
+
case "enableScreenshots": return "Screenshots";
|
|
471
|
+
default: return setting;
|
|
472
|
+
}
|
|
473
|
+
},
|
|
474
|
+
_toolbarSettingCurrentValue(setting) {
|
|
475
|
+
switch (setting) {
|
|
476
|
+
case "accent": return this.accent;
|
|
477
|
+
case "position": return this.position;
|
|
478
|
+
case "size": return this.size;
|
|
479
|
+
case "fabVisible": return this.fabVisible;
|
|
480
|
+
case "enableScreenshots": return this.enableScreenshots;
|
|
481
|
+
default: return null;
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
_toolbarSettingDisplayValue(value) {
|
|
485
|
+
return value === true ? "true" : value === false ? "false" : String(value);
|
|
486
|
+
},
|
|
487
|
+
_toolbarSettingsMarkup() {
|
|
488
|
+
return [
|
|
489
|
+
"accent",
|
|
490
|
+
"position",
|
|
491
|
+
"size",
|
|
492
|
+
"fabVisible",
|
|
493
|
+
"enableScreenshots"
|
|
494
|
+
].map(setting => this._toolbarSettingsRowMarkup(setting)).join("");
|
|
495
|
+
},
|
|
496
|
+
_toolbarSettingsRowMarkup(setting) {
|
|
497
|
+
const current = this._toolbarSettingCurrentValue(setting);
|
|
498
|
+
const options = this._toolbarSettingOptions(setting);
|
|
499
|
+
const buttons = options.map(([value, label]) => {
|
|
500
|
+
const active = String(value) === String(current);
|
|
501
|
+
const valueAttr = this._toolbarSettingDisplayValue(value);
|
|
502
|
+
return `<button type="button" class="rm-chip${active ? " rm-chip-active" : " rm-chip-inactive"} rm-setting-chip" data-setting="${setting}" data-value="${this._esc(valueAttr)}"${active ? ` style="background:${this._accentBg()}"` : ""}>${this._esc(label)}</button>`;
|
|
503
|
+
}).join("");
|
|
504
|
+
return `
|
|
505
|
+
<div class="rm-settings-group">
|
|
506
|
+
<div class="rm-settings-label">${this._esc(this._toolbarSettingLabel(setting))}</div>
|
|
507
|
+
<div class="rm-settings-options">${buttons}</div>
|
|
508
|
+
</div>
|
|
509
|
+
`;
|
|
510
|
+
},
|
|
511
|
+
_toolbarSettingValue(setting, rawValue) {
|
|
512
|
+
if (setting === "fabVisible" || setting === "enableScreenshots") {
|
|
513
|
+
return rawValue === true || rawValue === "true";
|
|
514
|
+
}
|
|
515
|
+
return String(rawValue || "");
|
|
516
|
+
},
|
|
517
|
+
_setToolbarSetting(setting, rawValue) {
|
|
518
|
+
const value = this._toolbarSettingValue(setting, rawValue);
|
|
519
|
+
const next = Object.assign({}, this.toolbarSettings, { [setting]: value });
|
|
520
|
+
const normalized = this._normalizeToolbarSettings(next);
|
|
521
|
+
if (JSON.stringify(normalized) === JSON.stringify(this.toolbarSettings)) return;
|
|
522
|
+
if (!this._saveToolbarSettings(normalized)) return;
|
|
523
|
+
this.toolbarSettings = normalized;
|
|
524
|
+
this.destroy();
|
|
525
|
+
this.init(this._bootstrapOptions || {});
|
|
526
|
+
},
|
|
527
|
+
_toggleSettings() {
|
|
528
|
+
const panel = document.getElementById("rm-settings-panel");
|
|
529
|
+
const toggle = document.getElementById("rm-settings-toggle");
|
|
530
|
+
if (!panel) return;
|
|
531
|
+
panel.hidden = !panel.hidden;
|
|
532
|
+
this._settingsPanelOpen = !panel.hidden;
|
|
533
|
+
if (toggle) toggle.setAttribute("aria-expanded", String(!panel.hidden));
|
|
534
|
+
},
|
|
422
535
|
async _captureElement(element) {
|
|
423
536
|
try {
|
|
424
537
|
const rect = element.getBoundingClientRect();
|
|
@@ -3,12 +3,21 @@
|
|
|
3
3
|
const previousPathname = this._currentPathname;
|
|
4
4
|
const previousPageUrl = this._currentPageUrl;
|
|
5
5
|
const currentPageUrl = this._pageUrl();
|
|
6
|
+
this._bootstrapOptions = Object.assign({}, opts);
|
|
6
7
|
this.endpoint = opts.endpoint || "/feedback/api";
|
|
7
|
-
|
|
8
|
-
this.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
const savedSettings = this._loadToolbarSettings();
|
|
9
|
+
this.toolbarSettings = this._normalizeToolbarSettings({
|
|
10
|
+
accent: savedSettings.accent || opts.accent || "indigo",
|
|
11
|
+
position: savedSettings.position || opts.position || "bl",
|
|
12
|
+
size: savedSettings.size || opts.size || "default",
|
|
13
|
+
fabVisible: savedSettings.fabVisible != null ? savedSettings.fabVisible : (opts.fabVisible !== false),
|
|
14
|
+
enableScreenshots: savedSettings.enableScreenshots != null ? savedSettings.enableScreenshots : (opts.enableScreenshots !== false)
|
|
15
|
+
});
|
|
16
|
+
this.accent = this.toolbarSettings.accent || "indigo";
|
|
17
|
+
this.position = this.toolbarSettings.position || "bl";
|
|
18
|
+
this.size = this.toolbarSettings.size || "default";
|
|
19
|
+
this.fabVisible = this.toolbarSettings.fabVisible !== false;
|
|
20
|
+
this.enableScreenshots = this.toolbarSettings.enableScreenshots !== false;
|
|
12
21
|
this.legacyStorageEndpoint = opts.legacyStorageEndpoint || this.legacyStorageEndpoint;
|
|
13
22
|
this.healthIntervalMs = (opts.healthInterval || 60) * 1000;
|
|
14
23
|
|
|
@@ -84,6 +93,7 @@
|
|
|
84
93
|
if (pins) pins.remove();
|
|
85
94
|
const styles = document.getElementById("rm-toolbar-styles");
|
|
86
95
|
if (styles) styles.remove();
|
|
96
|
+
this._settingsPanelOpen = false;
|
|
87
97
|
},
|
|
88
98
|
});
|
|
89
99
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<turbo-frame id="detail-panel">
|
|
6
6
|
<div class="rm-detail">
|
|
7
7
|
<%# Close button %>
|
|
8
|
-
<button type="button" class="rm-back" onclick="var f=this.closest('turbo-frame'); f.innerHTML=''; f.classList.add('rm-panel-empty'); document.querySelectorAll('.rm-card-active').forEach(c => c.classList.remove('rm-card-active'));">✕ Close</button>
|
|
8
|
+
<button type="button" class="rm-back" onclick="var f=this.closest('turbo-frame'); if (this.closest('.rm-layout')) { f.innerHTML=''; f.classList.add('rm-panel-empty'); document.querySelectorAll('.rm-card-active').forEach(c => c.classList.remove('rm-card-active')); } else { window.location.href='<%= j(rails_markup.root_path) %>'; }">✕ Close</button>
|
|
9
9
|
|
|
10
10
|
<%# Header badges %>
|
|
11
11
|
<div class="rm-detail-header">
|
|
@@ -31,7 +31,7 @@ RailsMarkup.configure do |config|
|
|
|
31
31
|
# "tl" (top-left), "tr" (top-right). Default: "bl"
|
|
32
32
|
# config.toolbar_position = "bl"
|
|
33
33
|
|
|
34
|
-
# FAB button size: "default" (
|
|
34
|
+
# FAB button size: "default" (40px), "compact" (36px), "slim" (32px)
|
|
35
35
|
# config.toolbar_size = "default"
|
|
36
36
|
|
|
37
37
|
# "Back to app" link in the dashboard header.
|
|
@@ -31,7 +31,7 @@ module RailsMarkup
|
|
|
31
31
|
title: "Toolbar Size",
|
|
32
32
|
type: :select,
|
|
33
33
|
options: %w[slim compact default],
|
|
34
|
-
labels: { "slim" => "Slim (32px)", "compact" => "Compact (
|
|
34
|
+
labels: { "slim" => "Slim (32px)", "compact" => "Compact (36px)", "default" => "Default (40px)" }
|
|
35
35
|
},
|
|
36
36
|
fab: {
|
|
37
37
|
title: "Show Floating Button",
|
|
@@ -73,7 +73,7 @@ module RailsMarkup
|
|
|
73
73
|
# "tl" (top-left), "tr" (top-right). Default: "bl"
|
|
74
74
|
attr_reader :toolbar_position
|
|
75
75
|
|
|
76
|
-
# FAB button size: "default" (
|
|
76
|
+
# FAB button size: "default" (40px), "compact" (36px), "slim" (32px).
|
|
77
77
|
# Default: "default"
|
|
78
78
|
attr_reader :toolbar_size
|
|
79
79
|
|
data/lib/rails_markup/version.rb
CHANGED