hgfdh
This commit is contained in:
+129
-1
@@ -6915,6 +6915,9 @@ window.cancelAnimFrame = (function () {
|
||||
<button type="button" class="f0ck-tuner-subtab-btn" data-subtab="flashyank" title="Flash Yank: retro low-res / low-fps / few-colour video filter">
|
||||
<i class="fa-solid fa-bolt-lightning"></i> Flash Yank
|
||||
</button>
|
||||
<button type="button" class="f0ck-tuner-subtab-btn" data-subtab="laser" title="Laser cursor: colour, trail, glow, click and drag effects">
|
||||
<i class="fa-solid fa-wand-magic-sparkles"></i> Laser
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="f0ck-tuner-close" id="f0ck-tuner-close" title="Close">✕</button>
|
||||
</div>
|
||||
@@ -7069,6 +7072,26 @@ window.cancelAnimFrame = (function () {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pane: Laser cursor (window.f0ckLaser from laser-cursor.js; rows built from its schema) -->
|
||||
<div id="f0ck-tuner-pane-laser" class="f0ck-tuner-subtab-pane" style="display: none;">
|
||||
<div class="f0ck-tuner-body">
|
||||
<div class="f0ck-tuner-presets-bar">
|
||||
<div style="font-size: 11px; opacity: 0.85; font-weight: 700; display: flex; align-items: center; gap: 6px;">
|
||||
<i class="fa-solid fa-wand-magic-sparkles"></i> Laser cursor
|
||||
</div>
|
||||
<div class="f0ck-tuner-presets-actions">
|
||||
<button type="button" id="laser-tuner-reset" class="f0ck-tuner-btn-factory-reset" title="Reset all laser settings to their defaults"><i class="fa-solid fa-rotate-left"></i> Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f0ck-tuner-mode-bar" style="display: flex; gap: 6px; padding: 6px 12px; background: rgba(255,255,255,0.04); border-bottom: 1px solid rgba(255,255,255,0.08);">
|
||||
<button type="button" id="laser-btn-off" class="f0ck-tuner-mode-btn" style="flex: 1; padding: 6px 10px; font-size: 11px; text-align: center;">Off</button>
|
||||
<button type="button" id="laser-btn-on" class="f0ck-tuner-mode-btn" style="flex: 1; padding: 6px 10px; font-size: 11px; text-align: center;"><i class="fa-solid fa-wand-magic-sparkles"></i> On</button>
|
||||
</div>
|
||||
<div id="laser-tuner-rows"></div>
|
||||
<div id="laser-tuner-info" style="padding: 4px 12px 12px; font-size: 11px; opacity: 0.6; line-height: 1.4;"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// ── Sub-Tab Switching Logic ─────────────────────────────────────────────
|
||||
@@ -7095,7 +7118,7 @@ window.cancelAnimFrame = (function () {
|
||||
});
|
||||
|
||||
const savedSubtab = localStorage.getItem('f0ck_tuner_active_subtab');
|
||||
if (savedSubtab && (savedSubtab === 'audio' || savedSubtab === 'danmaku' || savedSubtab === 'background' || savedSubtab === 'flashyank')) {
|
||||
if (savedSubtab && (savedSubtab === 'audio' || savedSubtab === 'danmaku' || savedSubtab === 'background' || savedSubtab === 'flashyank' || savedSubtab === 'laser')) {
|
||||
switchSubtab(savedSubtab);
|
||||
}
|
||||
|
||||
@@ -7139,6 +7162,111 @@ window.cancelAnimFrame = (function () {
|
||||
render();
|
||||
})();
|
||||
|
||||
// ── Laser cursor pane (window.f0ckLaser from laser-cursor.js) ──────────
|
||||
// laser-cursor.js loads after this file: rows are built from its schema the first time the API
|
||||
// exists, and the pane re-reads whenever the tab is opened.
|
||||
(() => {
|
||||
const rowsEl = panel.querySelector('#laser-tuner-rows');
|
||||
const onBtn = panel.querySelector('#laser-btn-on');
|
||||
const offBtn = panel.querySelector('#laser-btn-off');
|
||||
const resetBtn = panel.querySelector('#laser-tuner-reset');
|
||||
const infoEl = panel.querySelector('#laser-tuner-info');
|
||||
if (!rowsEl || !onBtn) return;
|
||||
const api = () => window.f0ckLaser || null;
|
||||
const esc = (v) => String(v).replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<');
|
||||
const fmt = (row, v) => {
|
||||
const n = Number(v);
|
||||
const shown = (row.step && row.step < 1) ? n.toFixed(row.step < 0.1 ? 2 : 1) : String(Math.round(n));
|
||||
return shown + (row.unit || '');
|
||||
};
|
||||
|
||||
const build = () => {
|
||||
const a = api();
|
||||
if (!a || rowsEl.dataset.built) return;
|
||||
const st = a.getState();
|
||||
let html = '';
|
||||
a.schema.forEach(row => {
|
||||
if (row.section) { html += '<div class="f0ck-tuner-section-title">' + esc(row.section) + '</div>'; return; }
|
||||
const v = st[row.key];
|
||||
if (row.type === 'toggle') {
|
||||
html += '<div class="f0ck-tuner-row" data-laser-key="' + row.key + '">' +
|
||||
'<div class="f0ck-tuner-row-label"><span>' + esc(row.label) + '</span></div>' +
|
||||
'<div style="display: flex; gap: 6px;">' +
|
||||
'<button type="button" class="f0ck-tuner-mode-btn" data-laser-toggle="0" style="flex: 1; padding: 4px 8px; font-size: 11px;">Off</button>' +
|
||||
'<button type="button" class="f0ck-tuner-mode-btn" data-laser-toggle="1" style="flex: 1; padding: 4px 8px; font-size: 11px;">On</button>' +
|
||||
'</div></div>';
|
||||
} else if (row.type === 'color') {
|
||||
html += '<div class="f0ck-tuner-row" data-laser-key="' + row.key + '">' +
|
||||
'<div class="f0ck-tuner-row-label"><span>' + esc(row.label) + '</span><span data-laser-value>' + esc(v) + '</span></div>' +
|
||||
'<input type="color" value="' + esc(v) + '" style="width: 100%; height: 30px; padding: 2px 4px; border: 1px solid var(--nav-border-color, rgba(255,255,255,0.2)); background: var(--bg, #111); cursor: pointer;" />' +
|
||||
'</div>';
|
||||
} else {
|
||||
html += '<div class="f0ck-tuner-row" data-laser-key="' + row.key + '">' +
|
||||
'<div class="f0ck-tuner-row-label"><span>' + esc(row.label) + '</span><span data-laser-value>' + fmt(row, v) + '</span></div>' +
|
||||
'<input type="range" min="' + row.min + '" max="' + row.max + '" step="' + row.step + '" value="' + esc(v) + '" />' +
|
||||
'</div>';
|
||||
}
|
||||
});
|
||||
rowsEl.innerHTML = html;
|
||||
rowsEl.dataset.built = '1';
|
||||
|
||||
rowsEl.querySelectorAll('[data-laser-key]').forEach(rowEl => {
|
||||
const key = rowEl.dataset.laserKey;
|
||||
const row = a.schema.find(r => r.key === key);
|
||||
const valEl = rowEl.querySelector('[data-laser-value]');
|
||||
const input = rowEl.querySelector('input');
|
||||
if (input) {
|
||||
input.addEventListener('input', () => {
|
||||
if (valEl) valEl.textContent = row.type === 'color' ? input.value : fmt(row, input.value);
|
||||
if (api()) api().set(key, input.value);
|
||||
});
|
||||
}
|
||||
rowEl.querySelectorAll('[data-laser-toggle]').forEach(b => {
|
||||
b.addEventListener('click', () => { if (api()) api().set(key, +b.dataset.laserToggle); });
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const render = (st) => {
|
||||
const a = api();
|
||||
build();
|
||||
st = st || (a && a.getState());
|
||||
const ready = !!st;
|
||||
[onBtn, offBtn, resetBtn].forEach(el => { el.disabled = !ready; });
|
||||
if (!ready) { infoEl.textContent = 'The laser cursor is not loaded on this page.'; return; }
|
||||
onBtn.classList.toggle('active', !!st.enabled);
|
||||
offBtn.classList.toggle('active', !st.enabled);
|
||||
rowsEl.querySelectorAll('[data-laser-key]').forEach(rowEl => {
|
||||
const key = rowEl.dataset.laserKey;
|
||||
const row = a.schema.find(r => r.key === key);
|
||||
const v = st[key];
|
||||
const input = rowEl.querySelector('input');
|
||||
const valEl = rowEl.querySelector('[data-laser-value]');
|
||||
if (input && document.activeElement !== input) input.value = v;
|
||||
if (valEl) valEl.textContent = row.type === 'color' ? v : fmt(row, v);
|
||||
rowEl.querySelectorAll('[data-laser-toggle]').forEach(b => b.classList.toggle('active', +b.dataset.laserToggle === (st[key] ? 1 : 0)));
|
||||
// Custom colour only matters when the accent is off; rainbow speed only with rainbow on
|
||||
if (key === 'color') rowEl.style.opacity = st.useAccent ? '0.45' : '';
|
||||
if (key === 'rainbowSpeed') rowEl.style.opacity = st.rainbow ? '' : '0.45';
|
||||
});
|
||||
infoEl.textContent = st.supported
|
||||
? 'Changes apply live and are saved on this device.'
|
||||
: 'Only for mouse/trackpad without "reduce motion": settings are saved but the laser stays off here.';
|
||||
};
|
||||
|
||||
onBtn.addEventListener('click', () => { if (api()) api().setEnabled(true); });
|
||||
offBtn.addEventListener('click', () => { if (api()) api().setEnabled(false); });
|
||||
resetBtn.addEventListener('click', () => { if (api()) api().reset(); });
|
||||
const onChange = (e) => {
|
||||
if (!panel.isConnected) { window.removeEventListener('f0ck:laser_changed', onChange); return; }
|
||||
render(e.detail);
|
||||
};
|
||||
window.addEventListener('f0ck:laser_changed', onChange);
|
||||
const tabBtn = panel.querySelector('.f0ck-tuner-subtab-btn[data-subtab="laser"]');
|
||||
if (tabBtn) tabBtn.addEventListener('click', () => render());
|
||||
render();
|
||||
})();
|
||||
|
||||
// ── Einfach / Erweitert Toggle (Background Tab) ────────────────────────
|
||||
const bgBasicRows = panel.querySelector('#f0ck-bg-basic-rows');
|
||||
const bgAdvancedRows = panel.querySelector('#f0ck-bg-advanced-rows');
|
||||
|
||||
Reference in New Issue
Block a user