mirror of
https://github.com/ShinkoNet/Wplace-Overlay-Pro.git
synced 2026-01-11 22:40:37 +00:00
inject symbols into palette
This commit is contained in:
parent
5b12b51cf4
commit
00c8bd5aa2
3 changed files with 217 additions and 2 deletions
|
|
@ -6,6 +6,7 @@ import { createUI, updateUI } from './ui/panel';
|
|||
import { displayImageFromData } from './core/overlay';
|
||||
import { showToast } from './core/toast';
|
||||
import { urlToDataURL } from './core/gm';
|
||||
import { enablePaletteSymbols } from './core/palette-inject';
|
||||
|
||||
async function applyTemplateFromUrl() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
|
|
@ -64,6 +65,7 @@ export async function bootstrapApp() {
|
|||
createUI();
|
||||
setUpdateUI(() => updateUI());
|
||||
ensureHook();
|
||||
enablePaletteSymbols();
|
||||
await applyTemplateFromUrl();
|
||||
console.log('Overlay Pro UI ready.');
|
||||
}
|
||||
195
src/core/palette-inject.ts
Normal file
195
src/core/palette-inject.ts
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
import { WPLACE_FREE, WPLACE_PAID, SYMBOL_TILES, SYMBOL_W, SYMBOL_H } from './palette';
|
||||
import { config } from './store';
|
||||
|
||||
const ALL_COLORS = [...WPLACE_FREE, ...WPLACE_PAID];
|
||||
let paletteObserver: MutationObserver | null = null;
|
||||
let isInjected = false;
|
||||
|
||||
function createSymbolCanvas(colorIndex: number, _bgColor: string): HTMLCanvasElement {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 20;
|
||||
canvas.height = 20;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) throw new Error('Failed to get 2D context');
|
||||
|
||||
// Clear with transparency
|
||||
ctx.clearRect(0, 0, 20, 20);
|
||||
|
||||
if (colorIndex < SYMBOL_TILES.length) {
|
||||
const symbol = SYMBOL_TILES[colorIndex];
|
||||
const scale = 3;
|
||||
const offsetX = Math.floor((20 - SYMBOL_W * scale) / 2);
|
||||
const offsetY = Math.floor((20 - SYMBOL_H * scale) / 2);
|
||||
|
||||
// Draw white outline first (slightly larger)
|
||||
ctx.fillStyle = '#ffffff';
|
||||
for (let y = 0; y < SYMBOL_H; y++) {
|
||||
for (let x = 0; x < SYMBOL_W; x++) {
|
||||
const bitIndex = y * SYMBOL_W + x;
|
||||
const bit = (symbol >>> bitIndex) & 1;
|
||||
|
||||
if (bit) {
|
||||
ctx.fillRect(
|
||||
offsetX + x * scale - 1,
|
||||
offsetY + y * scale - 1,
|
||||
scale + 2,
|
||||
scale + 2
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw black symbol on top
|
||||
ctx.fillStyle = '#000000';
|
||||
for (let y = 0; y < SYMBOL_H; y++) {
|
||||
for (let x = 0; x < SYMBOL_W; x++) {
|
||||
const bitIndex = y * SYMBOL_W + x;
|
||||
const bit = (symbol >>> bitIndex) & 1;
|
||||
|
||||
if (bit) {
|
||||
ctx.fillRect(
|
||||
offsetX + x * scale,
|
||||
offsetY + y * scale,
|
||||
scale,
|
||||
scale
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
function getColorFromButton(button: HTMLElement): string | null {
|
||||
const style = button.getAttribute('style');
|
||||
if (!style) return null;
|
||||
|
||||
const match = style.match(/background:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
||||
if (!match) return null;
|
||||
|
||||
return `${match[1]},${match[2]},${match[3]}`;
|
||||
}
|
||||
|
||||
function findColorIndex(colorKey: string): number {
|
||||
return ALL_COLORS.findIndex(([r, g, b]) => `${r},${g},${b}` === colorKey);
|
||||
}
|
||||
|
||||
function injectSymbolsIntoPalette() {
|
||||
if (isInjected) return;
|
||||
|
||||
// Find all color buttons in the palette
|
||||
const colorButtons = document.querySelectorAll('button[id^="color-"]');
|
||||
|
||||
if (colorButtons.length === 0) return;
|
||||
|
||||
colorButtons.forEach((button) => {
|
||||
const htmlButton = button as HTMLElement;
|
||||
const colorKey = getColorFromButton(htmlButton);
|
||||
|
||||
if (!colorKey) return;
|
||||
|
||||
const colorIndex = findColorIndex(colorKey);
|
||||
if (colorIndex === -1) return;
|
||||
|
||||
// Check if symbol already exists
|
||||
if (htmlButton.querySelector('.symbol-overlay')) return;
|
||||
|
||||
// Create symbol overlay
|
||||
const symbolCanvas = createSymbolCanvas(colorIndex, colorKey);
|
||||
symbolCanvas.className = 'symbol-overlay';
|
||||
symbolCanvas.style.cssText = `
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
opacity: 0.9;
|
||||
`;
|
||||
|
||||
// Make button position relative if it isn't already
|
||||
const computedStyle = window.getComputedStyle(htmlButton);
|
||||
if (computedStyle.position === 'static') {
|
||||
htmlButton.style.position = 'relative';
|
||||
}
|
||||
|
||||
htmlButton.appendChild(symbolCanvas);
|
||||
});
|
||||
|
||||
isInjected = true;
|
||||
}
|
||||
|
||||
function cleanupSymbols() {
|
||||
const symbols = document.querySelectorAll('.symbol-overlay');
|
||||
symbols.forEach(symbol => symbol.remove());
|
||||
isInjected = false;
|
||||
}
|
||||
|
||||
function startPaletteWatcher() {
|
||||
if (paletteObserver) return;
|
||||
|
||||
paletteObserver = new MutationObserver((mutations) => {
|
||||
let shouldCheck = false;
|
||||
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.type === 'childList') {
|
||||
// Check if palette was added or removed
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
const element = node as Element;
|
||||
if (element.querySelector('button[id^="color-"]') ||
|
||||
element.matches('button[id^="color-"]')) {
|
||||
shouldCheck = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mutation.removedNodes.forEach((node) => {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
const element = node as Element;
|
||||
if (element.querySelector('.symbol-overlay') ||
|
||||
element.matches('.symbol-overlay')) {
|
||||
isInjected = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (shouldCheck && config.overlayMode === 'minify' && config.minifyStyle === 'symbols') {
|
||||
// Small delay to ensure DOM is fully updated
|
||||
setTimeout(injectSymbolsIntoPalette, 100);
|
||||
}
|
||||
});
|
||||
|
||||
paletteObserver.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
}
|
||||
|
||||
export function enablePaletteSymbols() {
|
||||
startPaletteWatcher();
|
||||
|
||||
// Try to inject immediately if palette is already open
|
||||
if (config.overlayMode === 'minify' && config.minifyStyle === 'symbols') {
|
||||
setTimeout(injectSymbolsIntoPalette, 500);
|
||||
}
|
||||
}
|
||||
|
||||
export function disablePaletteSymbols() {
|
||||
if (paletteObserver) {
|
||||
paletteObserver.disconnect();
|
||||
paletteObserver = null;
|
||||
}
|
||||
cleanupSymbols();
|
||||
}
|
||||
|
||||
export function updatePaletteSymbols() {
|
||||
cleanupSymbols();
|
||||
|
||||
if (config.overlayMode === 'minify' && config.minifyStyle === 'symbols') {
|
||||
setTimeout(injectSymbolsIntoPalette, 100);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import { extractPixelCoords } from '../core/overlay';
|
|||
import { buildCCModal, openCCModal } from './ccModal';
|
||||
import { buildRSModal, openRSModal } from './rsModal';
|
||||
import { EV_ANCHOR_SET, EV_AUTOCAP_CHANGED } from '../core/events';
|
||||
import { updatePaletteSymbols } from '../core/palette-inject';
|
||||
|
||||
let panelEl: HTMLDivElement | null = null;
|
||||
|
||||
|
|
@ -314,14 +315,31 @@ function addEventListeners(panel: HTMLDivElement) {
|
|||
saveConfig(['overlayMode']);
|
||||
ensureHook();
|
||||
updateUI();
|
||||
updatePaletteSymbols();
|
||||
});
|
||||
});
|
||||
|
||||
const styleDotsEl = $('op-style-dots') as HTMLInputElement | null;
|
||||
styleDotsEl?.addEventListener('change', () => { if (styleDotsEl.checked) { config.minifyStyle = 'dots'; saveConfig(['minifyStyle']); clearOverlayCache(); ensureHook(); } });
|
||||
styleDotsEl?.addEventListener('change', () => {
|
||||
if (styleDotsEl.checked) {
|
||||
config.minifyStyle = 'dots';
|
||||
saveConfig(['minifyStyle']);
|
||||
clearOverlayCache();
|
||||
ensureHook();
|
||||
updatePaletteSymbols();
|
||||
}
|
||||
});
|
||||
|
||||
const styleSymbolsEl = $('op-style-symbols') as HTMLInputElement | null;
|
||||
styleSymbolsEl?.addEventListener('change', () => { if (styleSymbolsEl.checked) { config.minifyStyle = 'symbols'; saveConfig(['minifyStyle']); clearOverlayCache(); ensureHook(); } });
|
||||
styleSymbolsEl?.addEventListener('change', () => {
|
||||
if (styleSymbolsEl.checked) {
|
||||
config.minifyStyle = 'symbols';
|
||||
saveConfig(['minifyStyle']);
|
||||
clearOverlayCache();
|
||||
ensureHook();
|
||||
updatePaletteSymbols();
|
||||
}
|
||||
});
|
||||
|
||||
$('op-autocap-toggle')?.addEventListener('click', () => { config.autoCapturePixelUrl = !config.autoCapturePixelUrl; saveConfig(['autoCapturePixelUrl']); ensureHook(); updateUI(); });
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue