mirror of
https://github.com/Azornes/Comfyui-LayerForge.git
synced 2026-03-21 20:52:12 -03:00
modernized the "Custom Shape Menu"
I updated src/css/custom_shape_menu.css with new styles for a modern look and feel, and I refactored src/CustomShapeMenu.ts to use a new HTML structure for the checkboxes that works with the updated CSS. The menu should now be fully functional with the new design.
This commit is contained in:
@@ -61,10 +61,8 @@ export class CustomShapeMenu {
|
|||||||
featureContainer.id = 'shape-mask-feature-container';
|
featureContainer.id = 'shape-mask-feature-container';
|
||||||
featureContainer.className = 'feature-container';
|
featureContainer.className = 'feature-container';
|
||||||
// Add main auto-apply checkbox to the new container
|
// Add main auto-apply checkbox to the new container
|
||||||
const checkboxContainer = this._createCheckbox(() => `${this.canvas.autoApplyShapeMask ? "☑" : "☐"} Auto-apply shape mask`, () => {
|
const checkboxContainer = this._createCheckbox('auto-apply-checkbox', () => this.canvas.autoApplyShapeMask, 'Auto-apply shape mask', (e) => {
|
||||||
// Always hide any active shape preview lines first to prevent them from getting stuck
|
this.canvas.autoApplyShapeMask = e.target.checked;
|
||||||
this.canvas.maskTool.hideShapePreview();
|
|
||||||
this.canvas.autoApplyShapeMask = !this.canvas.autoApplyShapeMask;
|
|
||||||
if (this.canvas.autoApplyShapeMask) {
|
if (this.canvas.autoApplyShapeMask) {
|
||||||
this.canvas.maskTool.applyShapeMask();
|
this.canvas.maskTool.applyShapeMask();
|
||||||
log.info("Auto-apply shape mask enabled - mask applied automatically");
|
log.info("Auto-apply shape mask enabled - mask applied automatically");
|
||||||
@@ -80,8 +78,8 @@ export class CustomShapeMenu {
|
|||||||
}, "Automatically applies a mask based on the custom output area shape. When enabled, the mask will be applied to all layers within the shape boundary.");
|
}, "Automatically applies a mask based on the custom output area shape. When enabled, the mask will be applied to all layers within the shape boundary.");
|
||||||
featureContainer.appendChild(checkboxContainer);
|
featureContainer.appendChild(checkboxContainer);
|
||||||
// Add expansion checkbox
|
// Add expansion checkbox
|
||||||
const expansionContainer = this._createCheckbox(() => `${this.canvas.shapeMaskExpansion ? "☑" : "☐"} Expand/Contract mask`, () => {
|
const expansionContainer = this._createCheckbox('expansion-checkbox', () => this.canvas.shapeMaskExpansion, 'Expand/Contract mask', (e) => {
|
||||||
this.canvas.shapeMaskExpansion = !this.canvas.shapeMaskExpansion;
|
this.canvas.shapeMaskExpansion = e.target.checked;
|
||||||
this._updateUI();
|
this._updateUI();
|
||||||
if (this.canvas.autoApplyShapeMask) {
|
if (this.canvas.autoApplyShapeMask) {
|
||||||
this.canvas.maskTool.hideShapePreview();
|
this.canvas.maskTool.hideShapePreview();
|
||||||
@@ -89,7 +87,6 @@ export class CustomShapeMenu {
|
|||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
}
|
}
|
||||||
}, "Dilate (expand) or erode (contract) the shape mask. Positive values expand the mask outward, negative values shrink it inward.");
|
}, "Dilate (expand) or erode (contract) the shape mask. Positive values expand the mask outward, negative values shrink it inward.");
|
||||||
expansionContainer.id = 'expansion-checkbox';
|
|
||||||
featureContainer.appendChild(expansionContainer);
|
featureContainer.appendChild(expansionContainer);
|
||||||
// Add expansion slider container
|
// Add expansion slider container
|
||||||
const expansionSliderContainer = document.createElement('div');
|
const expansionSliderContainer = document.createElement('div');
|
||||||
@@ -154,8 +151,8 @@ export class CustomShapeMenu {
|
|||||||
expansionSliderContainer.appendChild(expansionValueDisplay);
|
expansionSliderContainer.appendChild(expansionValueDisplay);
|
||||||
featureContainer.appendChild(expansionSliderContainer);
|
featureContainer.appendChild(expansionSliderContainer);
|
||||||
// Add feather checkbox
|
// Add feather checkbox
|
||||||
const featherContainer = this._createCheckbox(() => `${this.canvas.shapeMaskFeather ? "☑" : "☐"} Feather edges`, () => {
|
const featherContainer = this._createCheckbox('feather-checkbox', () => this.canvas.shapeMaskFeather, 'Feather edges', (e) => {
|
||||||
this.canvas.shapeMaskFeather = !this.canvas.shapeMaskFeather;
|
this.canvas.shapeMaskFeather = e.target.checked;
|
||||||
this._updateUI();
|
this._updateUI();
|
||||||
if (this.canvas.autoApplyShapeMask) {
|
if (this.canvas.autoApplyShapeMask) {
|
||||||
this.canvas.maskTool.hideShapePreview();
|
this.canvas.maskTool.hideShapePreview();
|
||||||
@@ -163,7 +160,6 @@ export class CustomShapeMenu {
|
|||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
}
|
}
|
||||||
}, "Softens the edges of the shape mask by creating a gradual transition from opaque to transparent.");
|
}, "Softens the edges of the shape mask by creating a gradual transition from opaque to transparent.");
|
||||||
featherContainer.id = 'feather-checkbox';
|
|
||||||
featureContainer.appendChild(featherContainer);
|
featureContainer.appendChild(featherContainer);
|
||||||
// Add feather slider container
|
// Add feather slider container
|
||||||
const featherSliderContainer = document.createElement('div');
|
const featherSliderContainer = document.createElement('div');
|
||||||
@@ -219,30 +215,19 @@ export class CustomShapeMenu {
|
|||||||
extensionContainer.id = 'output-area-extension-container';
|
extensionContainer.id = 'output-area-extension-container';
|
||||||
extensionContainer.className = 'feature-container';
|
extensionContainer.className = 'feature-container';
|
||||||
// Add main extension checkbox
|
// Add main extension checkbox
|
||||||
const extensionCheckboxContainer = this._createCheckbox(() => `${this.canvas.outputAreaExtensionEnabled ? "☑" : "☐"} Extend output area`, () => {
|
const extensionCheckboxContainer = this._createCheckbox('extension-checkbox', () => this.canvas.outputAreaExtensionEnabled, 'Extend output area', (e) => {
|
||||||
this.canvas.outputAreaExtensionEnabled = !this.canvas.outputAreaExtensionEnabled;
|
this.canvas.outputAreaExtensionEnabled = e.target.checked;
|
||||||
if (this.canvas.outputAreaExtensionEnabled) {
|
if (this.canvas.outputAreaExtensionEnabled) {
|
||||||
// When enabling, capture current canvas size as the baseline
|
this.canvas.originalCanvasSize = { width: this.canvas.width, height: this.canvas.height };
|
||||||
this.canvas.originalCanvasSize = {
|
|
||||||
width: this.canvas.width,
|
|
||||||
height: this.canvas.height
|
|
||||||
};
|
|
||||||
// Restore last saved extensions instead of starting from zero
|
|
||||||
this.canvas.outputAreaExtensions = { ...this.canvas.lastOutputAreaExtensions };
|
this.canvas.outputAreaExtensions = { ...this.canvas.lastOutputAreaExtensions };
|
||||||
log.info(`Captured current canvas size as baseline: ${this.canvas.width}x${this.canvas.height}`);
|
|
||||||
log.info(`Restored last extensions:`, this.canvas.outputAreaExtensions);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Save current extensions before disabling
|
|
||||||
this.canvas.lastOutputAreaExtensions = { ...this.canvas.outputAreaExtensions };
|
this.canvas.lastOutputAreaExtensions = { ...this.canvas.outputAreaExtensions };
|
||||||
// Reset current extensions when disabled (but keep the saved ones)
|
|
||||||
this.canvas.outputAreaExtensions = { top: 0, bottom: 0, left: 0, right: 0 };
|
this.canvas.outputAreaExtensions = { top: 0, bottom: 0, left: 0, right: 0 };
|
||||||
log.info(`Saved extensions for later:`, this.canvas.lastOutputAreaExtensions);
|
|
||||||
}
|
}
|
||||||
this._updateExtensionUI();
|
this._updateExtensionUI();
|
||||||
this._updateCanvasSize(); // Update canvas size when toggling
|
this._updateCanvasSize();
|
||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
log.info(`Output area extension ${this.canvas.outputAreaExtensionEnabled ? 'enabled' : 'disabled'}`);
|
|
||||||
}, "Allows extending the output area boundaries in all directions without changing the custom shape.");
|
}, "Allows extending the output area boundaries in all directions without changing the custom shape.");
|
||||||
extensionContainer.appendChild(extensionCheckboxContainer);
|
extensionContainer.appendChild(extensionCheckboxContainer);
|
||||||
// Create sliders container
|
// Create sliders container
|
||||||
@@ -333,26 +318,28 @@ export class CustomShapeMenu {
|
|||||||
// Add viewport change listener to update shape preview when zooming/panning
|
// Add viewport change listener to update shape preview when zooming/panning
|
||||||
this._addViewportChangeListener();
|
this._addViewportChangeListener();
|
||||||
}
|
}
|
||||||
_createCheckbox(textFn, clickHandler, tooltipText) {
|
_createCheckbox(id, getChecked, text, clickHandler, tooltipText) {
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('label');
|
||||||
container.className = 'checkbox-container';
|
container.className = 'checkbox-container';
|
||||||
container.onmouseover = () => {
|
container.htmlFor = id;
|
||||||
container.style.backgroundColor = '#555';
|
const input = document.createElement('input');
|
||||||
};
|
input.type = 'checkbox';
|
||||||
container.onmouseout = () => {
|
input.id = id;
|
||||||
container.style.backgroundColor = 'transparent';
|
input.checked = getChecked();
|
||||||
};
|
const customCheckbox = document.createElement('div');
|
||||||
const updateText = () => {
|
customCheckbox.className = 'custom-checkbox';
|
||||||
container.textContent = textFn();
|
const labelText = document.createElement('span');
|
||||||
};
|
labelText.textContent = text;
|
||||||
updateText();
|
container.appendChild(input);
|
||||||
|
container.appendChild(customCheckbox);
|
||||||
|
container.appendChild(labelText);
|
||||||
|
// Stop propagation to prevent menu from closing, but allow default checkbox behavior
|
||||||
container.onclick = (e) => {
|
container.onclick = (e) => {
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
clickHandler();
|
|
||||||
updateText();
|
|
||||||
};
|
};
|
||||||
// Add tooltip if provided
|
input.onchange = (e) => {
|
||||||
|
clickHandler(e);
|
||||||
|
};
|
||||||
if (tooltipText) {
|
if (tooltipText) {
|
||||||
this._addTooltip(container, tooltipText);
|
this._addTooltip(container, tooltipText);
|
||||||
}
|
}
|
||||||
@@ -361,16 +348,23 @@ export class CustomShapeMenu {
|
|||||||
_updateUI() {
|
_updateUI() {
|
||||||
if (!this.element)
|
if (!this.element)
|
||||||
return;
|
return;
|
||||||
// Toggle visibility of sub-options based on the main checkbox state
|
const setChecked = (id, checked) => {
|
||||||
const expansionCheckbox = this.element.querySelector('#expansion-checkbox');
|
const input = this.element.querySelector(`#${id}`);
|
||||||
|
if (input)
|
||||||
|
input.checked = checked;
|
||||||
|
};
|
||||||
|
setChecked('auto-apply-checkbox', this.canvas.autoApplyShapeMask);
|
||||||
|
setChecked('expansion-checkbox', this.canvas.shapeMaskExpansion);
|
||||||
|
setChecked('feather-checkbox', this.canvas.shapeMaskFeather);
|
||||||
|
setChecked('extension-checkbox', this.canvas.outputAreaExtensionEnabled);
|
||||||
|
const expansionCheckbox = this.element.querySelector('#expansion-checkbox')?.parentElement;
|
||||||
if (expansionCheckbox) {
|
if (expansionCheckbox) {
|
||||||
expansionCheckbox.style.display = this.canvas.autoApplyShapeMask ? 'block' : 'none';
|
expansionCheckbox.style.display = this.canvas.autoApplyShapeMask ? 'flex' : 'none';
|
||||||
}
|
}
|
||||||
const featherCheckbox = this.element.querySelector('#feather-checkbox');
|
const featherCheckbox = this.element.querySelector('#feather-checkbox')?.parentElement;
|
||||||
if (featherCheckbox) {
|
if (featherCheckbox) {
|
||||||
featherCheckbox.style.display = this.canvas.autoApplyShapeMask ? 'block' : 'none';
|
featherCheckbox.style.display = this.canvas.autoApplyShapeMask ? 'flex' : 'none';
|
||||||
}
|
}
|
||||||
// Update sliders visibility based on their respective checkboxes
|
|
||||||
const expansionSliderContainer = this.element.querySelector('#expansion-slider-container');
|
const expansionSliderContainer = this.element.querySelector('#expansion-slider-container');
|
||||||
if (expansionSliderContainer) {
|
if (expansionSliderContainer) {
|
||||||
expansionSliderContainer.style.display = (this.canvas.autoApplyShapeMask && this.canvas.shapeMaskExpansion) ? 'block' : 'none';
|
expansionSliderContainer.style.display = (this.canvas.autoApplyShapeMask && this.canvas.shapeMaskExpansion) ? 'block' : 'none';
|
||||||
@@ -379,22 +373,6 @@ export class CustomShapeMenu {
|
|||||||
if (featherSliderContainer) {
|
if (featherSliderContainer) {
|
||||||
featherSliderContainer.style.display = (this.canvas.autoApplyShapeMask && this.canvas.shapeMaskFeather) ? 'block' : 'none';
|
featherSliderContainer.style.display = (this.canvas.autoApplyShapeMask && this.canvas.shapeMaskFeather) ? 'block' : 'none';
|
||||||
}
|
}
|
||||||
// Update checkbox texts
|
|
||||||
const checkboxes = this.element.querySelectorAll('div[style*="cursor: pointer"]');
|
|
||||||
checkboxes.forEach((checkbox, index) => {
|
|
||||||
if (index === 0) { // Main checkbox
|
|
||||||
checkbox.textContent = `${this.canvas.autoApplyShapeMask ? "☑" : "☐"} Auto-apply shape mask`;
|
|
||||||
}
|
|
||||||
else if (index === 1) { // Expansion checkbox
|
|
||||||
checkbox.textContent = `${this.canvas.shapeMaskExpansion ? "☑" : "☐"} Dilate/Erode mask`;
|
|
||||||
}
|
|
||||||
else if (index === 2) { // Feather checkbox
|
|
||||||
checkbox.textContent = `${this.canvas.shapeMaskFeather ? "☑" : "☐"} Feather edges`;
|
|
||||||
}
|
|
||||||
else if (index === 3) { // Extension checkbox
|
|
||||||
checkbox.textContent = `${this.canvas.outputAreaExtensionEnabled ? "☑" : "☐"} Extend output area`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
_updateExtensionUI() {
|
_updateExtensionUI() {
|
||||||
if (!this.element)
|
if (!this.element)
|
||||||
|
|||||||
@@ -2,92 +2,165 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background-color: #333;
|
background-color: #2f2f2f;
|
||||||
color: white;
|
color: #e0e0e0;
|
||||||
padding: 8px 15px;
|
padding: 12px;
|
||||||
border-radius: 10px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
|
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
|
||||||
display: none;
|
display: none;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 10px;
|
||||||
font-family: sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||||
font-size: 12px;
|
font-size: 13px;
|
||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
border: 1px solid #555;
|
border: 1px solid #202020;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
min-width: 200px;
|
min-width: 220px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .menu-line {
|
#layerforge-custom-shape-menu .menu-line {
|
||||||
margin: 2px 0;
|
font-weight: 600;
|
||||||
line-height: 18px;
|
color: #4a90e2;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
border-bottom: 1px solid #444;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .feature-container {
|
#layerforge-custom-shape-menu .feature-container {
|
||||||
background-color: #282828;
|
background-color: #3a3a3a;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
margin-top: 6px;
|
padding: 10px;
|
||||||
padding: 4px 0;
|
border: 1px solid #4a4a4a;
|
||||||
border: 1px solid #444;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .slider-container {
|
#layerforge-custom-shape-menu .slider-container {
|
||||||
margin: 0 8px 6px 8px;
|
margin-top: 10px;
|
||||||
padding: 4px 8px;
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .slider-label {
|
#layerforge-custom-shape-menu .slider-label {
|
||||||
font-size: 11px;
|
font-size: 12px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 6px;
|
||||||
color: #ccc;
|
color: #e0e0e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu input[type="range"] {
|
#layerforge-custom-shape-menu input[type="range"] {
|
||||||
|
-webkit-appearance: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
background: #555;
|
background: #555;
|
||||||
outline: none;
|
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
outline: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#layerforge-custom-shape-menu input[type="range"]::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
background: #e0e0e0;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 2px solid #555;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
#layerforge-custom-shape-menu input[type="range"]::-webkit-slider-thumb:hover {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#layerforge-custom-shape-menu input[type="range"]::-moz-range-thumb {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
background: #e0e0e0;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 2px solid #555;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .slider-value-display {
|
#layerforge-custom-shape-menu .slider-value-display {
|
||||||
font-size: 10px;
|
font-size: 11px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 2px;
|
margin-top: 4px;
|
||||||
color: #aaa;
|
color: #bbb;
|
||||||
|
min-height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .extension-slider-container {
|
#layerforge-custom-shape-menu .extension-slider-container {
|
||||||
margin: 6px 0;
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .checkbox-container {
|
#layerforge-custom-shape-menu .checkbox-container {
|
||||||
margin: 6px 0 2px 0;
|
display: flex;
|
||||||
padding: 4px 8px;
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 6px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
line-height: 18px;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .checkbox-container:hover {
|
#layerforge-custom-shape-menu .checkbox-container:hover {
|
||||||
background-color: #555;
|
background-color: #4a4a4a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layerforge-custom-shape-menu .checkbox-container input[type="checkbox"] {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layerforge-custom-shape-menu .checkbox-container .custom-checkbox {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
border: 1px solid #666;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
position: relative;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layerforge-custom-shape-menu .checkbox-container input:checked ~ .custom-checkbox {
|
||||||
|
background-color: #3a76d6;
|
||||||
|
border-color: #3a76d6;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layerforge-custom-shape-menu .checkbox-container .custom-checkbox::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
left: 5px;
|
||||||
|
top: 1px;
|
||||||
|
width: 4px;
|
||||||
|
height: 9px;
|
||||||
|
border: solid white;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#layerforge-custom-shape-menu .checkbox-container input:checked ~ .custom-checkbox::after {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layerforge-tooltip {
|
.layerforge-tooltip {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
background-color: #1a1a1a;
|
background-color: #2f2f2f;
|
||||||
color: #ffffff;
|
color: #e0e0e0;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
max-width: 250px;
|
max-width: 250px;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.6);
|
box-shadow: 0 4px 12px rgba(0,0,0,0.4);
|
||||||
border: 1px solid #444;
|
border: 1px solid #202020;
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
@@ -86,13 +86,11 @@ export class CustomShapeMenu {
|
|||||||
|
|
||||||
// Add main auto-apply checkbox to the new container
|
// Add main auto-apply checkbox to the new container
|
||||||
const checkboxContainer = this._createCheckbox(
|
const checkboxContainer = this._createCheckbox(
|
||||||
() => `${this.canvas.autoApplyShapeMask ? "☑" : "☐"} Auto-apply shape mask`,
|
'auto-apply-checkbox',
|
||||||
() => {
|
() => this.canvas.autoApplyShapeMask,
|
||||||
// Always hide any active shape preview lines first to prevent them from getting stuck
|
'Auto-apply shape mask',
|
||||||
this.canvas.maskTool.hideShapePreview();
|
(e) => {
|
||||||
|
this.canvas.autoApplyShapeMask = (e.target as HTMLInputElement).checked;
|
||||||
this.canvas.autoApplyShapeMask = !this.canvas.autoApplyShapeMask;
|
|
||||||
|
|
||||||
if (this.canvas.autoApplyShapeMask) {
|
if (this.canvas.autoApplyShapeMask) {
|
||||||
this.canvas.maskTool.applyShapeMask();
|
this.canvas.maskTool.applyShapeMask();
|
||||||
log.info("Auto-apply shape mask enabled - mask applied automatically");
|
log.info("Auto-apply shape mask enabled - mask applied automatically");
|
||||||
@@ -102,7 +100,6 @@ export class CustomShapeMenu {
|
|||||||
this.canvas.shapeMaskFeather = false;
|
this.canvas.shapeMaskFeather = false;
|
||||||
log.info("Auto-apply shape mask disabled - mask area removed and sub-options reset.");
|
log.info("Auto-apply shape mask disabled - mask area removed and sub-options reset.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateUI();
|
this._updateUI();
|
||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
},
|
},
|
||||||
@@ -112,11 +109,12 @@ export class CustomShapeMenu {
|
|||||||
|
|
||||||
// Add expansion checkbox
|
// Add expansion checkbox
|
||||||
const expansionContainer = this._createCheckbox(
|
const expansionContainer = this._createCheckbox(
|
||||||
() => `${this.canvas.shapeMaskExpansion ? "☑" : "☐"} Expand/Contract mask`,
|
'expansion-checkbox',
|
||||||
() => {
|
() => this.canvas.shapeMaskExpansion,
|
||||||
this.canvas.shapeMaskExpansion = !this.canvas.shapeMaskExpansion;
|
'Expand/Contract mask',
|
||||||
|
(e) => {
|
||||||
|
this.canvas.shapeMaskExpansion = (e.target as HTMLInputElement).checked;
|
||||||
this._updateUI();
|
this._updateUI();
|
||||||
|
|
||||||
if (this.canvas.autoApplyShapeMask) {
|
if (this.canvas.autoApplyShapeMask) {
|
||||||
this.canvas.maskTool.hideShapePreview();
|
this.canvas.maskTool.hideShapePreview();
|
||||||
this.canvas.maskTool.applyShapeMask();
|
this.canvas.maskTool.applyShapeMask();
|
||||||
@@ -125,7 +123,6 @@ export class CustomShapeMenu {
|
|||||||
},
|
},
|
||||||
"Dilate (expand) or erode (contract) the shape mask. Positive values expand the mask outward, negative values shrink it inward."
|
"Dilate (expand) or erode (contract) the shape mask. Positive values expand the mask outward, negative values shrink it inward."
|
||||||
);
|
);
|
||||||
expansionContainer.id = 'expansion-checkbox';
|
|
||||||
featureContainer.appendChild(expansionContainer);
|
featureContainer.appendChild(expansionContainer);
|
||||||
|
|
||||||
// Add expansion slider container
|
// Add expansion slider container
|
||||||
@@ -205,11 +202,12 @@ export class CustomShapeMenu {
|
|||||||
|
|
||||||
// Add feather checkbox
|
// Add feather checkbox
|
||||||
const featherContainer = this._createCheckbox(
|
const featherContainer = this._createCheckbox(
|
||||||
() => `${this.canvas.shapeMaskFeather ? "☑" : "☐"} Feather edges`,
|
'feather-checkbox',
|
||||||
() => {
|
() => this.canvas.shapeMaskFeather,
|
||||||
this.canvas.shapeMaskFeather = !this.canvas.shapeMaskFeather;
|
'Feather edges',
|
||||||
|
(e) => {
|
||||||
|
this.canvas.shapeMaskFeather = (e.target as HTMLInputElement).checked;
|
||||||
this._updateUI();
|
this._updateUI();
|
||||||
|
|
||||||
if (this.canvas.autoApplyShapeMask) {
|
if (this.canvas.autoApplyShapeMask) {
|
||||||
this.canvas.maskTool.hideShapePreview();
|
this.canvas.maskTool.hideShapePreview();
|
||||||
this.canvas.maskTool.applyShapeMask();
|
this.canvas.maskTool.applyShapeMask();
|
||||||
@@ -218,7 +216,6 @@ export class CustomShapeMenu {
|
|||||||
},
|
},
|
||||||
"Softens the edges of the shape mask by creating a gradual transition from opaque to transparent."
|
"Softens the edges of the shape mask by creating a gradual transition from opaque to transparent."
|
||||||
);
|
);
|
||||||
featherContainer.id = 'feather-checkbox';
|
|
||||||
featureContainer.appendChild(featherContainer);
|
featureContainer.appendChild(featherContainer);
|
||||||
|
|
||||||
// Add feather slider container
|
// Add feather slider container
|
||||||
@@ -288,32 +285,21 @@ export class CustomShapeMenu {
|
|||||||
|
|
||||||
// Add main extension checkbox
|
// Add main extension checkbox
|
||||||
const extensionCheckboxContainer = this._createCheckbox(
|
const extensionCheckboxContainer = this._createCheckbox(
|
||||||
() => `${this.canvas.outputAreaExtensionEnabled ? "☑" : "☐"} Extend output area`,
|
'extension-checkbox',
|
||||||
() => {
|
() => this.canvas.outputAreaExtensionEnabled,
|
||||||
this.canvas.outputAreaExtensionEnabled = !this.canvas.outputAreaExtensionEnabled;
|
'Extend output area',
|
||||||
|
(e) => {
|
||||||
if (this.canvas.outputAreaExtensionEnabled) {
|
this.canvas.outputAreaExtensionEnabled = (e.target as HTMLInputElement).checked;
|
||||||
// When enabling, capture current canvas size as the baseline
|
if (this.canvas.outputAreaExtensionEnabled) {
|
||||||
this.canvas.originalCanvasSize = {
|
this.canvas.originalCanvasSize = { width: this.canvas.width, height: this.canvas.height };
|
||||||
width: this.canvas.width,
|
|
||||||
height: this.canvas.height
|
|
||||||
};
|
|
||||||
// Restore last saved extensions instead of starting from zero
|
|
||||||
this.canvas.outputAreaExtensions = { ...this.canvas.lastOutputAreaExtensions };
|
this.canvas.outputAreaExtensions = { ...this.canvas.lastOutputAreaExtensions };
|
||||||
log.info(`Captured current canvas size as baseline: ${this.canvas.width}x${this.canvas.height}`);
|
|
||||||
log.info(`Restored last extensions:`, this.canvas.outputAreaExtensions);
|
|
||||||
} else {
|
} else {
|
||||||
// Save current extensions before disabling
|
|
||||||
this.canvas.lastOutputAreaExtensions = { ...this.canvas.outputAreaExtensions };
|
this.canvas.lastOutputAreaExtensions = { ...this.canvas.outputAreaExtensions };
|
||||||
// Reset current extensions when disabled (but keep the saved ones)
|
|
||||||
this.canvas.outputAreaExtensions = { top: 0, bottom: 0, left: 0, right: 0 };
|
this.canvas.outputAreaExtensions = { top: 0, bottom: 0, left: 0, right: 0 };
|
||||||
log.info(`Saved extensions for later:`, this.canvas.lastOutputAreaExtensions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateExtensionUI();
|
this._updateExtensionUI();
|
||||||
this._updateCanvasSize(); // Update canvas size when toggling
|
this._updateCanvasSize();
|
||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
log.info(`Output area extension ${this.canvas.outputAreaExtensionEnabled ? 'enabled' : 'disabled'}`);
|
|
||||||
},
|
},
|
||||||
"Allows extending the output area boundaries in all directions without changing the custom shape."
|
"Allows extending the output area boundaries in all directions without changing the custom shape."
|
||||||
);
|
);
|
||||||
@@ -424,31 +410,41 @@ export class CustomShapeMenu {
|
|||||||
this._addViewportChangeListener();
|
this._addViewportChangeListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _createCheckbox(textFn: () => string, clickHandler: () => void, tooltipText?: string): HTMLDivElement {
|
private _createCheckbox(
|
||||||
const container = document.createElement('div');
|
id: string,
|
||||||
|
getChecked: () => boolean,
|
||||||
|
text: string,
|
||||||
|
clickHandler: (e: Event) => void,
|
||||||
|
tooltipText?: string
|
||||||
|
): HTMLLabelElement {
|
||||||
|
const container = document.createElement('label');
|
||||||
container.className = 'checkbox-container';
|
container.className = 'checkbox-container';
|
||||||
|
container.htmlFor = id;
|
||||||
|
|
||||||
container.onmouseover = () => {
|
const input = document.createElement('input');
|
||||||
container.style.backgroundColor = '#555';
|
input.type = 'checkbox';
|
||||||
|
input.id = id;
|
||||||
|
input.checked = getChecked();
|
||||||
|
|
||||||
|
const customCheckbox = document.createElement('div');
|
||||||
|
customCheckbox.className = 'custom-checkbox';
|
||||||
|
|
||||||
|
const labelText = document.createElement('span');
|
||||||
|
labelText.textContent = text;
|
||||||
|
|
||||||
|
container.appendChild(input);
|
||||||
|
container.appendChild(customCheckbox);
|
||||||
|
container.appendChild(labelText);
|
||||||
|
|
||||||
|
// Stop propagation to prevent menu from closing, but allow default checkbox behavior
|
||||||
|
container.onclick = (e: MouseEvent) => {
|
||||||
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
container.onmouseout = () => {
|
input.onchange = (e: Event) => {
|
||||||
container.style.backgroundColor = 'transparent';
|
clickHandler(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateText = () => {
|
|
||||||
container.textContent = textFn();
|
|
||||||
};
|
|
||||||
|
|
||||||
updateText();
|
|
||||||
container.onclick = (e: MouseEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
clickHandler();
|
|
||||||
updateText();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add tooltip if provided
|
|
||||||
if (tooltipText) {
|
if (tooltipText) {
|
||||||
this._addTooltip(container, tooltipText);
|
this._addTooltip(container, tooltipText);
|
||||||
}
|
}
|
||||||
@@ -458,19 +454,27 @@ export class CustomShapeMenu {
|
|||||||
|
|
||||||
private _updateUI(): void {
|
private _updateUI(): void {
|
||||||
if (!this.element) return;
|
if (!this.element) return;
|
||||||
|
|
||||||
|
const setChecked = (id: string, checked: boolean) => {
|
||||||
|
const input = this.element!.querySelector(`#${id}`) as HTMLInputElement;
|
||||||
|
if (input) input.checked = checked;
|
||||||
|
};
|
||||||
|
|
||||||
// Toggle visibility of sub-options based on the main checkbox state
|
setChecked('auto-apply-checkbox', this.canvas.autoApplyShapeMask);
|
||||||
const expansionCheckbox = this.element.querySelector('#expansion-checkbox') as HTMLElement;
|
setChecked('expansion-checkbox', this.canvas.shapeMaskExpansion);
|
||||||
|
setChecked('feather-checkbox', this.canvas.shapeMaskFeather);
|
||||||
|
setChecked('extension-checkbox', this.canvas.outputAreaExtensionEnabled);
|
||||||
|
|
||||||
|
const expansionCheckbox = this.element.querySelector('#expansion-checkbox')?.parentElement as HTMLElement;
|
||||||
if (expansionCheckbox) {
|
if (expansionCheckbox) {
|
||||||
expansionCheckbox.style.display = this.canvas.autoApplyShapeMask ? 'block' : 'none';
|
expansionCheckbox.style.display = this.canvas.autoApplyShapeMask ? 'flex' : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
const featherCheckbox = this.element.querySelector('#feather-checkbox') as HTMLElement;
|
const featherCheckbox = this.element.querySelector('#feather-checkbox')?.parentElement as HTMLElement;
|
||||||
if (featherCheckbox) {
|
if (featherCheckbox) {
|
||||||
featherCheckbox.style.display = this.canvas.autoApplyShapeMask ? 'block' : 'none';
|
featherCheckbox.style.display = this.canvas.autoApplyShapeMask ? 'flex' : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update sliders visibility based on their respective checkboxes
|
|
||||||
const expansionSliderContainer = this.element.querySelector('#expansion-slider-container') as HTMLElement;
|
const expansionSliderContainer = this.element.querySelector('#expansion-slider-container') as HTMLElement;
|
||||||
if (expansionSliderContainer) {
|
if (expansionSliderContainer) {
|
||||||
expansionSliderContainer.style.display = (this.canvas.autoApplyShapeMask && this.canvas.shapeMaskExpansion) ? 'block' : 'none';
|
expansionSliderContainer.style.display = (this.canvas.autoApplyShapeMask && this.canvas.shapeMaskExpansion) ? 'block' : 'none';
|
||||||
@@ -480,20 +484,6 @@ export class CustomShapeMenu {
|
|||||||
if (featherSliderContainer) {
|
if (featherSliderContainer) {
|
||||||
featherSliderContainer.style.display = (this.canvas.autoApplyShapeMask && this.canvas.shapeMaskFeather) ? 'block' : 'none';
|
featherSliderContainer.style.display = (this.canvas.autoApplyShapeMask && this.canvas.shapeMaskFeather) ? 'block' : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update checkbox texts
|
|
||||||
const checkboxes = this.element.querySelectorAll('div[style*="cursor: pointer"]');
|
|
||||||
checkboxes.forEach((checkbox, index) => {
|
|
||||||
if (index === 0) { // Main checkbox
|
|
||||||
checkbox.textContent = `${this.canvas.autoApplyShapeMask ? "☑" : "☐"} Auto-apply shape mask`;
|
|
||||||
} else if (index === 1) { // Expansion checkbox
|
|
||||||
checkbox.textContent = `${this.canvas.shapeMaskExpansion ? "☑" : "☐"} Dilate/Erode mask`;
|
|
||||||
} else if (index === 2) { // Feather checkbox
|
|
||||||
checkbox.textContent = `${this.canvas.shapeMaskFeather ? "☑" : "☐"} Feather edges`;
|
|
||||||
} else if (index === 3) { // Extension checkbox
|
|
||||||
checkbox.textContent = `${this.canvas.outputAreaExtensionEnabled ? "☑" : "☐"} Extend output area`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateExtensionUI(): void {
|
private _updateExtensionUI(): void {
|
||||||
|
|||||||
@@ -2,92 +2,165 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background-color: #333;
|
background-color: #2f2f2f;
|
||||||
color: white;
|
color: #e0e0e0;
|
||||||
padding: 8px 15px;
|
padding: 12px;
|
||||||
border-radius: 10px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
|
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
|
||||||
display: none;
|
display: none;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 10px;
|
||||||
font-family: sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||||
font-size: 12px;
|
font-size: 13px;
|
||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
border: 1px solid #555;
|
border: 1px solid #202020;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
min-width: 200px;
|
min-width: 220px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .menu-line {
|
#layerforge-custom-shape-menu .menu-line {
|
||||||
margin: 2px 0;
|
font-weight: 600;
|
||||||
line-height: 18px;
|
color: #4a90e2;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
border-bottom: 1px solid #444;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .feature-container {
|
#layerforge-custom-shape-menu .feature-container {
|
||||||
background-color: #282828;
|
background-color: #3a3a3a;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
margin-top: 6px;
|
padding: 10px;
|
||||||
padding: 4px 0;
|
border: 1px solid #4a4a4a;
|
||||||
border: 1px solid #444;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .slider-container {
|
#layerforge-custom-shape-menu .slider-container {
|
||||||
margin: 0 8px 6px 8px;
|
margin-top: 10px;
|
||||||
padding: 4px 8px;
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .slider-label {
|
#layerforge-custom-shape-menu .slider-label {
|
||||||
font-size: 11px;
|
font-size: 12px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 6px;
|
||||||
color: #ccc;
|
color: #e0e0e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu input[type="range"] {
|
#layerforge-custom-shape-menu input[type="range"] {
|
||||||
|
-webkit-appearance: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
background: #555;
|
background: #555;
|
||||||
outline: none;
|
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
outline: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#layerforge-custom-shape-menu input[type="range"]::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
background: #e0e0e0;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 2px solid #555;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
#layerforge-custom-shape-menu input[type="range"]::-webkit-slider-thumb:hover {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#layerforge-custom-shape-menu input[type="range"]::-moz-range-thumb {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
background: #e0e0e0;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 2px solid #555;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .slider-value-display {
|
#layerforge-custom-shape-menu .slider-value-display {
|
||||||
font-size: 10px;
|
font-size: 11px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 2px;
|
margin-top: 4px;
|
||||||
color: #aaa;
|
color: #bbb;
|
||||||
|
min-height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .extension-slider-container {
|
#layerforge-custom-shape-menu .extension-slider-container {
|
||||||
margin: 6px 0;
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .checkbox-container {
|
#layerforge-custom-shape-menu .checkbox-container {
|
||||||
margin: 6px 0 2px 0;
|
display: flex;
|
||||||
padding: 4px 8px;
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 6px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
line-height: 18px;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#layerforge-custom-shape-menu .checkbox-container:hover {
|
#layerforge-custom-shape-menu .checkbox-container:hover {
|
||||||
background-color: #555;
|
background-color: #4a4a4a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layerforge-custom-shape-menu .checkbox-container input[type="checkbox"] {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layerforge-custom-shape-menu .checkbox-container .custom-checkbox {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
border: 1px solid #666;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
position: relative;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layerforge-custom-shape-menu .checkbox-container input:checked ~ .custom-checkbox {
|
||||||
|
background-color: #3a76d6;
|
||||||
|
border-color: #3a76d6;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layerforge-custom-shape-menu .checkbox-container .custom-checkbox::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
left: 5px;
|
||||||
|
top: 1px;
|
||||||
|
width: 4px;
|
||||||
|
height: 9px;
|
||||||
|
border: solid white;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#layerforge-custom-shape-menu .checkbox-container input:checked ~ .custom-checkbox::after {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layerforge-tooltip {
|
.layerforge-tooltip {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
background-color: #1a1a1a;
|
background-color: #2f2f2f;
|
||||||
color: #ffffff;
|
color: #e0e0e0;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
max-width: 250px;
|
max-width: 250px;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.6);
|
box-shadow: 0 4px 12px rgba(0,0,0,0.4);
|
||||||
border: 1px solid #444;
|
border: 1px solid #202020;
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user