Skip to content

Commit f78e741

Browse files
committed
Split floating panel even further.
1 parent cad43d2 commit f78e741

File tree

3 files changed

+473
-1
lines changed

3 files changed

+473
-1
lines changed

floating-panel-ui-creation.js

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
// floating-panel-ui-creation.js
2+
// Version: 1.0
3+
//
4+
// Documentation:
5+
// This file contains UI creation and basic behavior methods for the floating panel.
6+
// It handles creation of the panel DOM structure, profile switcher, drag functionality,
7+
// positioning at the cursor, and the creation of the toggle button.
8+
//
9+
// Methods included:
10+
// - createFloatingPanel(): Creates the panel element with header, content container, and footer.
11+
// - createProfileSwitcher(): Builds the profile dropdown in the panel footer.
12+
// - makeDraggable(): Enables drag functionality on an element via a handle.
13+
// - positionPanelAtCursor(): Positions the panel relative to the mouse cursor.
14+
// - createPanelToggleButton(): Creates the toggle button for summoning the floating panel.
15+
//
16+
// Dependencies:
17+
// - floating-panel.js provides the namespace (window.MaxExtensionFloatingPanel).
18+
// - utils.js for logging via logConCgp.
19+
//
20+
'use strict';
21+
22+
/**
23+
* Creates the floating panel element and appends it to the document body.
24+
* (UI creation, header, content container, and footer.)
25+
*/
26+
window.MaxExtensionFloatingPanel.createFloatingPanel = function() {
27+
// Check if panel already exists
28+
if (this.panelElement) {
29+
return this.panelElement;
30+
}
31+
32+
// Create the main panel element
33+
const panel = document.createElement('div');
34+
panel.id = 'max-extension-floating-panel';
35+
panel.style.cssText = `
36+
position: fixed;
37+
top: 0;
38+
left: 0;
39+
width: ${this.currentPanelSettings.width}px;
40+
height: ${this.currentPanelSettings.height}px;
41+
background-color: rgba(50, 50, 50, ${this.currentPanelSettings.opacity});
42+
border: 1px solid #444;
43+
border-radius: 8px;
44+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
45+
display: flex;
46+
flex-direction: column;
47+
z-index: 10000;
48+
overflow: hidden;
49+
resize: both;
50+
pointer-events: auto;
51+
color: rgba(255, 255, 255, 0.9);
52+
`;
53+
54+
// Create the panel header for dragging
55+
const panelHeader = document.createElement('div');
56+
panelHeader.id = 'max-extension-floating-panel-header';
57+
panelHeader.style.cssText = `
58+
padding: 8px 12px;
59+
background-color: rgba(40, 40, 40, ${this.currentPanelSettings.opacity + 0.1});
60+
cursor: move;
61+
display: flex;
62+
justify-content: space-between;
63+
align-items: center;
64+
user-select: none;
65+
`;
66+
67+
// Create panel title
68+
const panelTitle = document.createElement('div');
69+
panelTitle.textContent = 'OneClickPrompts';
70+
panelTitle.style.cssText = `
71+
font-weight: bold;
72+
font-size: 14px;
73+
color: rgba(255, 255, 255, 0.9);
74+
`;
75+
76+
// Create close button
77+
const closeButton = document.createElement('button');
78+
closeButton.innerHTML = '×';
79+
closeButton.style.cssText = `
80+
background: none;
81+
border: none;
82+
font-size: 20px;
83+
cursor: pointer;
84+
padding: 0 5px;
85+
line-height: 1;
86+
color: rgba(255, 255, 255, 0.9);
87+
`;
88+
closeButton.title = 'Close panel and return to injected buttons';
89+
closeButton.addEventListener('click', () => this.togglePanel());
90+
91+
// Add title and close button to header
92+
panelHeader.appendChild(panelTitle);
93+
panelHeader.appendChild(closeButton);
94+
95+
// Create content container for buttons
96+
const contentContainer = document.createElement('div');
97+
contentContainer.id = 'max-extension-floating-panel-content';
98+
contentContainer.style.cssText = `
99+
flex: 1;
100+
padding: 10px;
101+
overflow-y: auto;
102+
display: flex;
103+
flex-wrap: wrap;
104+
gap: 8px;
105+
align-content: flex-start;
106+
`;
107+
108+
// Create profile switcher footer
109+
const profileSwitcherContainer = document.createElement('div');
110+
profileSwitcherContainer.id = 'max-extension-profile-switcher';
111+
profileSwitcherContainer.style.cssText = `
112+
padding: 8px 12px;
113+
background-color: rgba(40, 40, 40, ${this.currentPanelSettings.opacity + 0.1});
114+
display: flex;
115+
justify-content: space-between;
116+
align-items: center;
117+
border-top: 1px solid rgba(100, 100, 100, 0.3);
118+
cursor: move;
119+
`;
120+
121+
// Add drag functionality to header and profile switcher (backup if header is off-screen)
122+
this.makeDraggable(panel, panelHeader);
123+
this.makeDraggable(panel, profileSwitcherContainer);
124+
125+
// Append elements to the panel
126+
panel.appendChild(panelHeader);
127+
panel.appendChild(contentContainer);
128+
panel.appendChild(profileSwitcherContainer);
129+
130+
// Append the panel to the document body
131+
document.body.appendChild(panel);
132+
133+
// Initially hide the panel
134+
panel.style.display = 'none';
135+
136+
// Add resize event listener to save dimensions
137+
panel.addEventListener('mouseup', () => {
138+
if (panel.style.width !== `${this.currentPanelSettings.width}px` ||
139+
panel.style.height !== `${this.currentPanelSettings.height}px`) {
140+
141+
this.currentPanelSettings.width = parseInt(panel.style.width);
142+
this.currentPanelSettings.height = parseInt(panel.style.height);
143+
this.debouncedSavePanelSettings();
144+
}
145+
});
146+
147+
this.panelElement = panel;
148+
return panel;
149+
};
150+
151+
/**
152+
* Creates the profile switcher UI inside the panel footer.
153+
*/
154+
window.MaxExtensionFloatingPanel.createProfileSwitcher = function() {
155+
const switcherContainer = document.getElementById('max-extension-profile-switcher');
156+
if (!switcherContainer) return;
157+
158+
// Clear existing content
159+
switcherContainer.innerHTML = '';
160+
161+
// Create profile label
162+
const profileLabel = document.createElement('div');
163+
profileLabel.textContent = 'Profile:';
164+
profileLabel.style.cssText = `
165+
font-size: 12px;
166+
color: rgba(255, 255, 255, 0.9);
167+
`;
168+
169+
// Create profile selector dropdown
170+
const profileSelector = document.createElement('select');
171+
profileSelector.id = 'max-extension-profile-selector';
172+
profileSelector.style.cssText = `
173+
background-color: rgba(60, 60, 60, 1);
174+
color: rgba(255, 255, 255, 0.9);
175+
border: 1px solid rgba(100, 100, 100, 0.5);
176+
border-radius: 4px;
177+
padding: 4px 8px;
178+
font-size: 12px;
179+
cursor: pointer;
180+
min-width: 120px;
181+
`;
182+
183+
// Prevent dragging when interacting with the dropdown
184+
profileSelector.addEventListener('mousedown', (event) => {
185+
event.stopPropagation();
186+
});
187+
profileSelector.addEventListener('click', (event) => {
188+
event.stopPropagation();
189+
});
190+
191+
// Populate the dropdown with available profiles
192+
this.availableProfiles.forEach(profileName => {
193+
const option = document.createElement('option');
194+
option.value = profileName;
195+
option.textContent = profileName;
196+
if (profileName === this.currentProfileName) {
197+
option.selected = true;
198+
}
199+
profileSelector.appendChild(option);
200+
});
201+
202+
// Add change event listener to the profile selector
203+
profileSelector.addEventListener('change', (event) => {
204+
const selectedProfileName = event.target.value;
205+
this.switchToProfile(selectedProfileName);
206+
});
207+
208+
// Append label and selector to the container
209+
switcherContainer.appendChild(profileLabel);
210+
switcherContainer.appendChild(profileSelector);
211+
};
212+
213+
/**
214+
* Makes an element draggable using a given handle element.
215+
*/
216+
window.MaxExtensionFloatingPanel.makeDraggable = function(element, handle) {
217+
let offsetX = 0;
218+
let offsetY = 0;
219+
220+
const startDrag = (e) => {
221+
e.preventDefault();
222+
offsetX = e.clientX - element.getBoundingClientRect().left;
223+
offsetY = e.clientY - element.getBoundingClientRect().top;
224+
document.addEventListener('mousemove', dragElement);
225+
document.addEventListener('mouseup', stopDrag);
226+
};
227+
228+
const dragElement = (e) => {
229+
e.preventDefault();
230+
element.style.left = (e.clientX - offsetX) + 'px';
231+
element.style.top = (e.clientY - offsetY) + 'px';
232+
};
233+
234+
const stopDrag = () => {
235+
document.removeEventListener('mousemove', dragElement);
236+
document.removeEventListener('mouseup', stopDrag);
237+
this.currentPanelSettings.posX = parseInt(element.style.left);
238+
this.currentPanelSettings.posY = parseInt(element.style.top);
239+
this.debouncedSavePanelSettings();
240+
};
241+
242+
handle.addEventListener('mousedown', startDrag);
243+
};
244+
245+
/**
246+
* Positions the floating panel at the mouse cursor's position.
247+
*/
248+
window.MaxExtensionFloatingPanel.positionPanelAtCursor = function(event) {
249+
if (!this.panelElement) return;
250+
const cursorX = event.clientX;
251+
const cursorY = event.clientY;
252+
this.panelElement.style.left = cursorX + 'px';
253+
this.panelElement.style.top = (cursorY - this.currentPanelSettings.height) + 'px';
254+
this.currentPanelSettings.posX = parseInt(this.panelElement.style.left);
255+
this.currentPanelSettings.posY = parseInt(this.panelElement.style.top);
256+
this.debouncedSavePanelSettings();
257+
};
258+
259+
/**
260+
* Creates a toggle button for the floating panel.
261+
*/
262+
window.MaxExtensionFloatingPanel.createPanelToggleButton = function() {
263+
const toggleButton = document.createElement('button');
264+
toggleButton.innerHTML = '🔼';
265+
toggleButton.style.cssText = `
266+
background-color: transparent;
267+
border: none;
268+
cursor: pointer;
269+
padding: 1px;
270+
font-size: 20px;
271+
margin-right: 5px;
272+
margin-bottom: 5px;
273+
`;
274+
toggleButton.title = 'Toggle floating button panel';
275+
276+
toggleButton.addEventListener('click', (event) => {
277+
this.togglePanel(event);
278+
});
279+
280+
return toggleButton;
281+
};

0 commit comments

Comments
 (0)