Improve background effects for light theme and fix mobile color picker
- WebGL shader: theme-aware blending (tint toward accent on light, additive glow on dark) with u_light uniform for proper light-theme visibility - Cards: translucent backgrounds only on entity cards when bg-anim is active, keeping modals/pickers/tab bars/header fully opaque - Running card border and tab indicator: boosted contrast for light theme - Header: backdrop-filter via pseudo-element to avoid breaking fixed tab-bar - Color picker: move popover to document.body on mobile as centered bottom-sheet - Add card: use --card-bg background and bolder + icon for visibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ uniform float u_time;
|
||||
uniform vec2 u_res;
|
||||
uniform vec3 u_accent;
|
||||
uniform vec3 u_bg;
|
||||
uniform float u_light; // 0.0 = dark theme, 1.0 = light theme
|
||||
uniform vec3 u_particles[${PARTICLE_COUNT}]; // xy = position (0-1), z = radius
|
||||
|
||||
// Simplex-style noise
|
||||
@@ -72,8 +73,12 @@ void main() {
|
||||
float colorMix = n2 * 0.5 + 0.5;
|
||||
vec3 color = mix(col1, col2, colorMix);
|
||||
|
||||
// Noise background
|
||||
vec3 result = mix(u_bg, u_bg + color * 0.6, glow * 0.14);
|
||||
float boost = 1.0 + u_light * 1.2; // 1.0 dark, 2.2 light
|
||||
|
||||
// Noise background: additive glow on dark, tint toward accent on light
|
||||
vec3 noiseDark = mix(u_bg, u_bg + color * 0.6, glow * 0.14);
|
||||
vec3 noiseLight = mix(u_bg, u_accent * 0.82, glow * 0.14 * boost);
|
||||
vec3 result = mix(noiseDark, noiseLight, u_light);
|
||||
|
||||
// Floating particles — accumulate glow from each
|
||||
float particleGlow = 0.0;
|
||||
@@ -90,20 +95,24 @@ void main() {
|
||||
particleColor += g * step(0.5, fract(float(i) * 0.5));
|
||||
}
|
||||
|
||||
// Mix particle colors: accent and white-ish accent
|
||||
// Dark: additive white-ish accent glow; Light: blend toward accent color
|
||||
vec3 pCol = mix(u_accent, mix(u_accent, vec3(1.0), 0.5), particleColor / max(particleGlow, 0.001));
|
||||
result += pCol * particleGlow * 0.5;
|
||||
float pI = particleGlow * 0.5;
|
||||
vec3 pDark = result + pCol * pI;
|
||||
vec3 pLight = mix(result, u_accent * 0.7, pI * boost * 0.35);
|
||||
result = mix(pDark, pLight, u_light);
|
||||
|
||||
gl_FragColor = vec4(result, 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
let _canvas, _gl, _prog;
|
||||
let _uTime, _uRes, _uAccent, _uBg, _uParticles;
|
||||
let _uTime, _uRes, _uAccent, _uBg, _uLight, _uParticles;
|
||||
let _raf = null;
|
||||
let _startTime = 0;
|
||||
let _accent = [76 / 255, 175 / 255, 80 / 255];
|
||||
let _bgColor = [26 / 255, 26 / 255, 26 / 255];
|
||||
let _isLight = 0.0;
|
||||
|
||||
// Particle state (CPU-side, positions in 0..1 UV space)
|
||||
const _particles = [];
|
||||
@@ -174,6 +183,7 @@ function _initGL() {
|
||||
_uRes = gl.getUniformLocation(_prog, 'u_res');
|
||||
_uAccent = gl.getUniformLocation(_prog, 'u_accent');
|
||||
_uBg = gl.getUniformLocation(_prog, 'u_bg');
|
||||
_uLight = gl.getUniformLocation(_prog, 'u_light');
|
||||
_uParticles = [];
|
||||
for (let i = 0; i < PARTICLE_COUNT; i++) {
|
||||
_uParticles.push(gl.getUniformLocation(_prog, `u_particles[${i}]`));
|
||||
@@ -202,6 +212,7 @@ function _draw(time) {
|
||||
gl.uniform2f(_uRes, _canvas.width, _canvas.height);
|
||||
gl.uniform3f(_uAccent, _accent[0], _accent[1], _accent[2]);
|
||||
gl.uniform3f(_uBg, _bgColor[0], _bgColor[1], _bgColor[2]);
|
||||
gl.uniform1f(_uLight, _isLight);
|
||||
|
||||
for (let i = 0; i < PARTICLE_COUNT; i++) {
|
||||
const p = _particles[i];
|
||||
@@ -241,6 +252,7 @@ export function updateBgAnimAccent(hex) {
|
||||
|
||||
export function updateBgAnimTheme(isDark) {
|
||||
_bgColor = isDark ? [26 / 255, 26 / 255, 26 / 255] : [245 / 255, 245 / 255, 245 / 255];
|
||||
_isLight = isDark ? 0.0 : 1.0;
|
||||
}
|
||||
|
||||
export function initBgAnim() {
|
||||
|
||||
@@ -88,15 +88,25 @@ window._cpToggle = function (id) {
|
||||
const card = pop.closest('.card, .template-card');
|
||||
if (card) card.classList.toggle('cp-elevated', true);
|
||||
|
||||
// On small screens, if inside an overflow container (e.g. header toolbar),
|
||||
// switch to fixed positioning so the popover isn't clipped.
|
||||
const wrapper = pop.closest('.color-picker-wrapper');
|
||||
if (wrapper && window.innerWidth <= 600) {
|
||||
const rect = wrapper.getBoundingClientRect();
|
||||
// On small/touch screens, move popover to body as a centered bottom-sheet
|
||||
// to avoid any parent overflow/containment/positioning issues.
|
||||
const isMobile = window.innerWidth <= 768 || ('ontouchstart' in window);
|
||||
if (isMobile && pop.parentElement !== document.body) {
|
||||
pop._cpOrigParent = pop.parentElement;
|
||||
pop._cpOrigNext = pop.nextSibling;
|
||||
document.body.appendChild(pop);
|
||||
}
|
||||
if (isMobile) {
|
||||
pop.style.position = 'fixed';
|
||||
pop.style.top = (rect.bottom + 4) + 'px';
|
||||
pop.style.right = Math.max(4, window.innerWidth - rect.right) + 'px';
|
||||
pop.style.left = 'auto';
|
||||
pop.style.left = '0';
|
||||
pop.style.right = '0';
|
||||
pop.style.top = 'auto';
|
||||
pop.style.bottom = '70px';
|
||||
pop.style.margin = '0 auto';
|
||||
pop.style.width = 'fit-content';
|
||||
pop.style.transform = 'none';
|
||||
pop.style.animation = 'none';
|
||||
pop.style.zIndex = '10000';
|
||||
pop.classList.add('cp-fixed');
|
||||
}
|
||||
|
||||
@@ -118,6 +128,18 @@ function _cpClosePopover(pop) {
|
||||
pop.style.top = '';
|
||||
pop.style.right = '';
|
||||
pop.style.left = '';
|
||||
pop.style.bottom = '';
|
||||
pop.style.transform = '';
|
||||
pop.style.animation = '';
|
||||
pop.style.margin = '';
|
||||
pop.style.width = '';
|
||||
pop.style.zIndex = '';
|
||||
// Return popover to its original parent
|
||||
if (pop._cpOrigParent) {
|
||||
pop._cpOrigParent.insertBefore(pop, pop._cpOrigNext || null);
|
||||
delete pop._cpOrigParent;
|
||||
delete pop._cpOrigNext;
|
||||
}
|
||||
}
|
||||
const card = pop.closest('.card, .template-card');
|
||||
if (card) card.classList.remove('cp-elevated');
|
||||
|
||||
Reference in New Issue
Block a user