Download
65 lines 1.9 KiBJavaScriptModified 2026-08-01 raw
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
// Shared pieces for percent-meter chips (volume, brightness): the
// collapsible percentage value, the peek-on-change reveal, and the
// segmented icon fill. Widgets compose these in their own create() —
// see volume.js and brightness.js.

export const METER_SETTINGS = [
  { key: "showPercent", label: "Show percent", type: "boolean", default: false },
  {
    key: "peekOnChange",
    label: "Show percent briefly on change",
    type: "boolean",
    default: true,
  },
];

// The collapsible "100%" value: fixed 4ch when shown, zero-width when
// the chip has the "compact" class.
export function meterValueCss(widgetClass) {
  return `
    .${widgetClass} .value {
      width: 4ch; /* "100%" */
      text-align: left;
      overflow: hidden;
      transition: width 200ms ease, opacity 200ms ease, margin-left 200ms ease;
    }
    /* Collapsed: zero width plus a negative margin to cancel the chip gap */
    .${widgetClass}.compact .value {
      width: 0;
      opacity: 0;
      margin-left: -5px;
    }
  `;
}

// Temporarily reveal the percentage after a change, then re-collapse.
// cancel() in the widget's destroy so the timer doesn't outlive the chip.
export function makePeek(el, ms = 5000) {
  let timer = null;
  return {
    show() {
      el.classList.remove("compact");
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => {
        el.classList.add("compact");
        timer = null;
      }, ms);
    },
    cancel() {
      if (timer) clearTimeout(timer);
      timer = null;
    },
  };
}

const clamp01 = (x) => Math.min(1, Math.max(0, x));

// Proportional icon fill: each element owns an equal slice of 0–100 and
// fades from minOpacity to full as the value sweeps through its slice.
export function segmentFill(els, percent, minOpacity) {
  const slice = 100 / els.length;
  els.forEach((el, i) => {
    const t = clamp01((percent - i * slice) / slice);
    el.style.opacity = (minOpacity + (1 - minOpacity) * t).toFixed(3);
  });
}