Meeting Countdown

Countdown to a scheduled time via widget-param.

timeschedule

Example

//
// ScriptWidget
// https://xnu.app/scriptwidget
//
// Meeting Countdown
// widget-param: "2026-02-01 09:30" or ISO string
//

const param = ($getenv("widget-param") || "").trim();
let target = null;

if (param) {
  const normalized = param.includes("T") ? param : param.replace(" ", "T");
  const parsed = new Date(normalized);
  if (!Number.isNaN(parsed.getTime())) {
    target = parsed;
  }
}

if (!target) {
  $render(
    <vstack frame="max" padding="12" background="#0f172a">
      <text font="caption" color="#94a3b8">Meeting Countdown</text>
      <text font="title3" color="#e2e8f0">Set widget-param</text>
      <text font="caption2" color="#64748b">Example: 2026-02-01 09:30</text>
    </vstack>
  );
} else {
  const now = new Date();
  const diffMs = target.getTime() - now.getTime();
  const diffMin = Math.max(0, Math.floor(diffMs / 60000));
  const diffHour = Math.floor(diffMin / 60);
  const diffDay = Math.floor(diffHour / 24);
  const hours = diffHour % 24;
  const minutes = diffMin % 60;

  $render(
    <vstack frame="max" padding="12" background="#1e293b">
      <text font="caption" color="#94a3b8">Next Meeting</text>
      <text font="title2" color="#e2e8f0">{diffDay}d {hours}h {minutes}m</text>
      <text font="caption2" color="#64748b">Target: {target.toLocaleString()}</text>
    </vstack>
  );
}
Templates live in Shared/ScriptWidgetRuntime/Resource/Script.bundle/template/ and can be imported directly into the app.