Mulai dalam 60 detik
Buka app Safar Widget → Skrip Baru → tempel kode di bawah → ▶ Run
(pratinjau + konsol) → Simpan → buat Instance → tahan layar utama →
tambah widget "Safar Widget" → Edit Widget → pilih instance-mu.
const w = Widget.create({ padding: 14, background: '#06201E' });
w.text('Halo dunia', { size: 18, weight: 'bold', color: '#FFFFFF' });
w.countdown('2027-01-01T00:00:00+07:00', { size: 14, color: '#34C759' });
Widget.present(w);
Model eksekusi: sinkron & berbatas waktu
- Skrip berjalan dari atas ke bawah lalu wajib memanggil
Widget.present(w)tepat sekali. Tidak adaasync/await—http.getJSON()memblokir sampai jawaban datang. - Budget 8 detik per eksekusi (jaringan + komputasi). Timeout
httpdefault 6 detik dan otomatis dipotong sisa budget. Loop tak berujung dihentikan dengan kesalahan yang jelas. - Cache-fallback otomatis: respons HTTP sukses disimpan; saat fetch gagal, skrip menerima data lama tanpa melihat error dan widget menampilkan lencana umur data. Skrip error total → tampilan sukses terakhir, bukan widget kosong.
- Jadwal render milik iOS (± 15–60 menit).
Widget.refreshAfter(menit)hanya saran (floor 15). Nodecountdowntetap berdetak hidup tanpa refresh.
API runtime
| API | Keterangan |
|---|---|
Widget.params | Objek parameter instance (diisi di app; per-widget) |
Widget.device | {family: 'small'|'medium'|'large', locale, darkMode} |
Widget.create(opts) | {padding, background (hex/Gradient), url, spacing, align} |
Widget.present(w) / Widget.refreshAfter(menit) | Serahkan pohon / saran refresh berikutnya |
http.getJSON(url, o) · getText · post | o = {timeout, headers}; gagal & tanpa cache → throw |
cache.get(k) / cache.set(k, v) | KV kecil per-skrip, persisten lintas render |
console.log(...) | Tampil di konsol editor (di widget dibuang) |
Gradient.vertical(...) / horizontal | Latar gradien untuk background |
Node tampilan (builder)
| Pemanggilan | Hasil |
|---|---|
w.text(teks, props) | Teks. props: {size, weight: 'regular'|'medium'|'semibold'|'bold', color, lineLimit, minScale} |
w.countdown(tanggal, props) | Hitung mundur hidup (berdetak tanpa refresh); ISO 8601 atau Date |
w.clock(props) | Jam saat render (statis — batas WidgetKit) |
w.progress(nilai, props) | Bar 0–1. {color, track, height} |
w.spacer(px?) / w.divider(props) | Celah tetap / fleksibel; garis pemisah |
w.hstack(opts) / w.vstack(opts) | Kembalikan builder anak; {spacing, align} |
Modul bawaan (offline, tanpa unduhan)
| Modul | API |
|---|---|
Sholat | hitung({tanggal:'YYYY-MM-DD', lat, lng, tzMenit, metode:'kemenag'|'mwl', koreksiMenit}) → {subuh…isya}, tiap item {jam:'HH:mm', menit}. Perkiraan astronomis — selalu tampilkan anjuran mengikuti jadwal masjid. |
Hijriah | dariMasehi(date, koreksiHari) → {hari, bulan, tahun, namaBulan, namaHari, teks} (tabular; sediakan koreksi ±2 hari) |
Bedanya dari Scriptable
Skrip Scriptable tidak bisa ditempel langsung —
Color, ListWidget,
Request, Font adalah API milik app Scriptable. Safar Widget memakai API
sendiri yang lebih kecil supaya satu skrip kelak berjalan identik di iOS dan Android.
Perbedaan utama: sinkron (tanpa await), builder deklaratif (bukan addText/addStack imperatif),
cache-fallback bawaan runtime, token/rahasia lewat parameter instance — bukan diedit di
dalam skrip.
Berbagi skrip
Dari editor, tombol Bagikan membungkus skrip sebagai berkas
.safarwidget yang bisa dikirim lewat WhatsApp/AirDrop/Files. Penerima yang
sudah memasang Safar Widget cukup mengetuk berkasnya — app terbuka dan menampilkan
seluruh isi skrip untuk diperiksa sebelum disimpan. Bundel tidak pernah
memuat parameter instance (di sanalah token/kunci API tinggal), jadi rahasia
pengirim tidak ikut terbagi. Tautan safarwidget://impor?d=<base64url>
juga didukung.
Kiat
- Rahasia (API key, token) taruh di parameter instance — skrip tetap bersih dan aman dibagikan.
- Parameter wajib yang kosong → tampilkan kartu petunjuk, jangan biarkan error. Semua template katalog memakai pola ini.
- Batasi fitur bahasa ke ES2020 tanpa
Intl(paritas Android kelak). Format angka pakaiString(n).replace(/\B(?=(\d{3})+(?!\d))/g, '.'). - Sesuaikan tampilan per ukuran lewat
Widget.device.family. - Widget adalah dasbor, bukan alarm — iOS yang menentukan waktu refresh.
Contoh siap pakai
Semua pola di atas hidup di katalog template — dari kartu teks sederhana sampai dashboard haji & umroh multi-API, dan setiap template divalidasi mesin terhadap runtime yang sama dengan aplikasi.
Khusus pelaku haji & umroh ada grup tersendiri, tersaring per peran: jamaah (kartu identitas, panduan thawaf & sa'i, jadwal obat), travel (kursi paket, pelunasan, visa, manifest, target penjualan), land arrangement (okupansi hotel, kedatangan grup, armada, katering), muttawif (headcount, agenda, briefing cuaca), dan ustadz (materi kajian, dalil manasik, progres bimbingan).