اصنع واجهتك الخاصة

ابنِ واجهات مؤشراتك الخاصة بـ HTML وCSS وJavaScript. كل واجهة تعمل مع كل مصدر، من البطارية إلى الأرقام التي ترسلها بنفسك.

بداية سريعة

  1. أنشئ واجهة: في الإعدادات، انقر إنشاء واجهة… (Option-Command-N). ينشئ Multimeter مجلدًا من ملفات البداية تستخدم بيانات الإصدار 2 مسبقًا.
  2. عدّل الملفات: يعرض Multimeter المجلد في Finder. عدّل الملفات في أي محرر شيفرة.
  3. شاهد التغييرات فورًا: يعيد Multimeter تحميل واجهتك في كل مرة تحفظ فيها. جرّبها على مصادر مختلفة في إضافة مؤشر… أو تخصيص هذا المؤشر….
  4. شاركه: اضغط المجلد في Finder، وغيّر اسم ملف ‎.zip إلى .multimeter، وأرسله إلى المعرض. يمكن لأي شخص إضافته عبر استيراد… (Command-O) أو بالنقر المزدوج على الملف.

كيف يعمل المؤشر

المؤشر في شريط القوائم هو واجهة ومصدر وإعدادات الشخص. الواجهة هي مجلدك: صفحة ويب صغيرة يحمّلها Multimeter في عرض شفاف ارتفاعه 22 نقطة، وعرضه بقدر width في ملف البيان. والمصدر هو ما يقيسه المؤشر، ويختاره الشخص عند إضافة المؤشر.

كلما تغيّر شيء، يضبط Multimeter قيمة window.meterData ويرسل حدث meterUpdate. لا تحتاج واجهتك إلى معرفة مصدر الأرقام: ارسم level (من 0 إلى 1) واعرض formatted، وستعمل مع المعالج والشبكة والمؤقت والبطارية على حد سواء.

بنية الملفات

كل واجهة مجلد يحتوي على:

my-meter/
├── manifest.json    # name, size, which sources it's made for
├── index.html       # the page Multimeter loads
├── styles.css
└── meter.js         # listens for meterUpdate and draws

manifest.json

يصف ملف البيان واجهتك، ويخبر Multimeter بعرضها والغرض الذي صُنعت له:

{
  "name": "My Meter",
  "description": "What it shows, in one line.",
  "version": "1.0.0",
  "author": "Your Name",
  "apiVersion": 2,
  "sources": ["any"],
  "defaultSource": "cpu",
  "width": 60,
  "minWidth": 40,
  "maxWidth": 100,
  "supportsLightMode": true,
  "supportsDarkMode": true
}
المفتاحالنوعالمعنى
namestringيظهر في قائمة الواجهات وفي المعرض.
descriptionstringسطر واحد عمّا تعرضه الواجهة.
versionstringرقم إصدارك، مثل 1.0.0.
authorstringاسمك، ويظهر في المعرض.
apiVersion2اضبطه على 2 للبيانات الموصوفة في هذه الصفحة.
sourcesstring[]["any"] لواجهة تستطيع رسم أي مصدر، أو قائمة بمعرّفات المصادر مثل ["battery"] أو ["battery", "countdown", "timer"]. لا يعرض Multimeter واجهتك إلا لتلك المصادر.
defaultSourcestringالمصدر الذي يُختار عندما يضيف أحدهم واجهتك أول مرة، مثل "cpu".
widthnumberالعرض بالنقاط. الارتفاع دائمًا 22.
minWidth / maxWidthnumberأضيق وأعرض ما يمكن للشخص ضبطه في تخصيص.
supportsLightMode / supportsDarkModebooleanهل الواجهة مصممة لشريط القوائم الفاتح والداكن.

ملف البيان الذي لا يحتوي على apiVersion وsources يُعامَل كواجهة مخصصة للبطارية أولًا تعمل مع أي مصدر رغم ذلك، فتستمر المؤشرات المصنوعة للإصدارات السابقة في العمل.

بيانات المؤشر

يضع Multimeter البيانات الحالية في window.meterData ويرسلها من جديد عند كل تغيير. إليك كل ما فيها (الإصدار 2 من الواجهة البرمجية):

window.meterData = {
  apiVersion: 2,
  source: "cpu",            // what this meter measures
  sourceName: "CPU",        // that source's name, translated
  label: "CPU",             // the meter's label ("" if the person cleared it)
  value: 23.4,              // raw value in `unit` (null if unavailable)
  min: 0, max: 100,         // the range `level` is measured against
  level: 0.234,             // value placed in the range, 0 to 1
  formatted: "23%",         // ready to show, unit included, in the person's language
  unit: "%",                // "%", "W", "B/s", "rpm", "s", or your own
  state: "normal",          // "normal", "warning" or "critical"
  tint: null,               // "#30D158" if the person picked a color
  history: [0.21, 0.25],    // up to 60 recent levels, oldest first
  warningLevel: 0.7,        // alert levels on the same 0 to 1 scale (or null)
  criticalLevel: 0.9,
  alertDirection: "above",  // "above" or "below" (or null)
  available: true,          // false when the source can't be read right now
  colorScheme: "dark",      // the menu bar: "light" or "dark"
  reduceMotion: false,      // System Settings > Accessibility > Reduce motion
  strings: { timeLeft: "left" },
  battery: {                // always the Mac's battery, whatever the source
    level: 0.82, percentage: 82, isCharging: false, isPluggedIn: false,
    hasBattery: true, timeRemaining: 312, timeToFullCharge: null,
    formattedTime: "5:12", cycleCount: 212, health: 0.94, temperature: 30.5
  },
  // Version 1 fields, so battery meters keep working with any source:
  percentage: 23, isCharging: false, isPluggedIn: false,
  timeRemaining: null, timeToFullCharge: null, formattedTime: null,
  cycleCount: 212, health: 0.94, temperature: 30.5, hasBattery: true
}
الحقلالمعنى
sourceمعرّف المصدر (انظر الجدول أدناه). وsourceName اسمه المترجم.
labelتسمية المؤشر، مثل CPU أو DOWN. يمكن للشخص تغييرها أو مسحها، لذا قد تكون نصًا فارغًا.
valueالقراءة الخام بوحدة unit، أو null. ومع min وmax تحصل على الصورة كاملة.
levelالقيمة موضوعة في النطاق من 0 إلى 1، ومحصورة فيه. معظم الواجهات لا تحتاج إلا إلى هذه.
formattedالقراءة كنص مع الوحدة، منسقة حسب لغة الشخص: 23%، 12.4 W، 1.2 MB/s، 4:12.
unit%، W، B/s، rpm، s (للمؤقتات والعد التنازلي)، أو نص فارغ، أو وحدة يحددها الشخص.
statenormal أو warning أو critical، حسب مستويات التنبيه التي ضبطها الشخص. لوّن واجهتك بناءً عليها.
tintلون مثل #30D158 اختاره الشخص، أو null لاستخدام ألوان واجهتك.
historyحتى 60 مستوى حديثًا (من 0 إلى 1)، الأقدم أولًا، للرسوم البيانية.
warningLevelيضع warningLevel وcriticalLevel مستويات التنبيه على مقياس 0 إلى 1 نفسه الذي يستخدمه level، ويحدد alertDirection هل تنطلق التنبيهات above (فوقها) أو below (تحتها). الثلاثة تكون null إذا لم يكن للمؤشر تنبيهات.
availablefalse عندما يتعذر قراءة المصدر الآن: لا توجد بطارية، أو الملحق مطفأ، أو عنوان الويب لا يستجيب. اعرض شرطة.
colorSchemeمظهر شريط القوائم، light أو dark. يتبع الخلفية، لا إعداد النظام وحده.
reduceMotiontrue عند تشغيل تقليل الحركة. تخطَّ الحركات.
batteryبطارية جهاز Mac، موجودة دائمًا أيًّا كان ما يقيسه المؤشر: الشحن، وقيد الشحن، والتوصيل بالكهرباء، والوقت المتبقي، والوقت حتى الامتلاء، والدورات، والصحة، ودرجة الحرارة.

الاستماع إلى التحديثات

ارسم مرة بما هو موجود في window.meterData، ثم من جديد عند كل meterUpdate. اضبط window.meterReady = true عندما تكون جاهزًا لاستقبال البيانات.

function render(data) {
  // draw the meter from data.level, data.formatted, data.state ...
}

window.addEventListener('meterUpdate', (e) => render(e.detail));
render(window.meterData || { level: 0.5, formatted: '50%', state: 'normal' });
window.meterReady = true;

المصادر

هذه هي المصادر التي يمكن أن تكون للمؤشر. ترى واجهتك المعرّف في source وتحصل على formatted مكتوبًا مسبقًا، لذا نادرًا ما تحتاج إلى معاملتها بشكل مختلف.

المصدرsourceunitشكل formatted
البطاريةbattery"%"82%
ملحق Bluetoothbluetooth"%"64%
استهلاك الطاقةpower"W"12.4 W
المعالجcpu"%"23%
الذاكرةmemory"%"71%
مساحة القرصdisk"%"58%
الضغط الحراريthermal""عادي, مقبول, مرتفع, حرج
سرعة المروحة*fan"rpm"2,400 rpm
الشبكةnetwork"B/s"1.2 MB/s, 340 KB/s
المؤقتtimer"s"24:51
العد التنازليcountdown"s"3d 4h, 4:12, 12:05
تقدّم اليومprogress"%"63%
القيمة المرسلةpush""42
عنوان ويبurl""1,284
ملفfile""12
سكربت*script""412

* تحتاج سرعة المروحة والسكربتات إلى إصدار التنزيل المباشر من Multimeter. لا يستطيع إصدار Mac App Store قراءة مستشعرات المروحة ولا تشغيل سكربتاتك؛ استخدم هناك قيمة مرسلة أو ملفًا بدلًا منها.

تمتد النسب المئوية دائمًا من 0 إلى 100. يتدرج استهلاك الطاقة والشبكة وسرعة المروحة حسب ذروتها الأخيرة ما لم يضبط الشخص نطاقًا. للضغط الحراري أربع درجات، لذا يكون level إما 0 أو 0.33 أو 0.67 أو 1. في المؤقتات والعد التنازلي، level هو نسبة الوقت المتبقي وvalue هو الثواني المتبقية.

التنبيهات والألوان

يمكن أن يكون لكل مؤشر مستوى تحذير ومستوى حرج يضبطهما الشخص (البطارية افتراضيًا تحت 20% و10%، والمعالج فوق 70% و90%، والقرص فوق 85% و95%). يحسب Multimeter قيمة state نيابة عنك. يجب أن تبدو الواجهة هادئة عندما تكون normal، وأن يعلو صوتها كلما انتقلت إلى warning وcritical، وأن تستخدم tint عندما يختار الشخص لونًا:

document.body.classList.remove('warning', 'critical');
if (data.state !== 'normal') document.body.classList.add(data.state);

// The person's color wins over the face's own
if (data.tint) document.body.style.setProperty('--accent', data.tint);
else document.body.style.removeProperty('--accent');
body.warning  { --accent: #ff9f0a; }
body.critical { --accent: #ff453a; }

تريد رسم مناطق التنبيه على مقياس، مثل قرص ينتهي بالأحمر؟ استخدم warningLevel وcriticalLevel وalertDirection.

السجل

يحتوي history على ما يصل إلى 60 مستوى حديثًا، الأقدم أولًا، على مقياس 0 إلى 1 مسبقًا. أضف level الحالي إلى النهاية فيصبح لديك رسم بياني. مثال History Graph أدناه يرسم واحدًا.

تفاصيل البطارية

ما زالت البطارية مميزة. data.battery هي دائمًا بطارية جهاز Mac، أيًّا كان ما يقيسه المؤشر، لذا تستطيع أي واجهة عرض رمز الشحن. يجب أن تذكر الواجهة المصنوعة للبطارية فقط "sources": ["battery"] في ملف البيان. القيمتان timeRemaining وtimeToFullCharge بالدقائق، وتكونان null ما دام macOS يقدّر الوقت.

// A battery-only face: "sources": ["battery"] in manifest.json
const b = data.battery;
bolt.hidden = !b.isCharging;
time.textContent = b.isCharging
  ? (b.timeToFullCharge ? `${b.timeToFullCharge} min to full` : '')
  : (b.formattedTime ?? '');

الواجهات المكتوبة للإصدار 1 تقرأ percentage وisCharging وformattedTime في المستوى الأعلى. وما زالت تُرسل: في مصدر البطارية هي قيم البطارية نفسها، وفي المصادر الأخرى تكون isCharging هي false وformattedTime هو الوقت المتبقي في المؤقت أو العد التنازلي (h:mm)، وإلا فهي null.

بياناتك الخاصة

أربعة مصادر تعرض أرقامًا تقدمها أنت: قيمة مرسلة، أو عنوان ويب، أو ملف، أو سكربت. تتعامل معها واجهتك مثل أي مصدر آخر.

أرسل قيمة برابط

افتح رابط multimeter://set من أي مكان: Terminal، أو سكربت shell، أو الاختصارات (فتح عناوين URL)، أو Raycast، أو مهمة cron، أو سكربت بناء. أضف مؤشرًا بمصدر القيمة المرسلة وبالمفتاح نفسه، فيتحدّث لحظة فتح الرابط. يُبقي open -g تطبيق Multimeter في الخلفية.

# Set a value (the meter shows the "deploys" key)
open -g "multimeter://set?key=deploys&value=42"

# Range, label, unit and your own text ride along
open -g "multimeter://set?key=coffee&value=3&min=0&max=5&label=Coffee&unit=cups"
open -g "multimeter://set?key=build&value=0.8&max=1&formatted=80%25%20done"
المعاملالمعنى
keyالمؤشر المقصود. لا تفرّق المفاتيح بين الأحرف الكبيرة والصغيرة.
valueالرقم. إلزامي.
min / maxالنطاق، حتى يخرج level صحيحًا. الافتراضي من 0 إلى 100.
labelنص تسمية المؤشر.
unitوحدة تُضاف بعد الرقم، مثل cups. استخدم % للنسبة المئوية.
formattedنصك الخاص لـ formatted، ويُستخدم بدلًا من الرقم.

القيم المرسلة تعمل في إصدار Mac App Store أيضًا. يتذكر Multimeter آخر قيمة لكل مفتاح.

عناوين الويب والملفات والسكربتات

الثلاثة تقرأ المخرجات نفسها: رقمًا عاديًا، أو JSON يحتوي على value وأي من الإضافات. كل شيء ما عدا value اختياري.

42
42.5
42%

{"value": 42, "min": 0, "max": 100, "label": "Deploys", "unit": "", "formatted": "42 left"}

تشير إلى JSON أكبر، مثل استجابة API؟ أعطِ المؤشر مسار مفتاح وسيستخرج الرقم:

{"data": {"count": 17}}                → key path  data.count
{"items": [{"value": 9.5}]}             → key path  items.0.value
  • عنوان الويب: يُجلب كل فترة تختارها، بحد أقصى مرة كل 30 ثانية (كل 5 دقائق ما لم تغيّر ذلك).
  • الملف: يُقرأ من جديد كلما تغيّر. مفيد لأي شيء يستطيع كتابة ملف.
  • السكربت: أمر shell يعمل عبر zsh كل فترة تختارها (كل 30 ثانية ما لم تغيّر ذلك). يعرض Multimeter الرقم الذي يطبعه. مجلدات Homebrew موجودة في PATH، والأمر الذي يستغرق أكثر من 10 ثوانٍ يُوقف.
# Open pull requests waiting on you (direct download version)
gh pr list --search "review-requested:@me" --json number --jq length

# Free memory pressure as a percentage
memory_pressure | awk '/percentage/ {print 100 - $5}'

يستطيع إصدار Mac App Store استخدام عناوين الويب والملفات، لكن ليس السكربتات. للسكربتات هناك، اجعل سكربتك يرسل رابطًا أو يكتب ملفًا.

شريط القوائم الفاتح والداكن

يكون شريط القوائم فاتحًا أو داكنًا حسب الخلفية. يضيف Multimeter الصنف light-mode أو dark-mode إلى body، ويضبط colorScheme في البيانات، كما يطابق prefers-color-scheme شريط القوائم أيضًا. استخدم ما يناسبك:

/* Dark menu bar (the default) */
body { color: white; }

/* Light menu bar */
body.light-mode { color: black; }

/* Same thing with the media query, which follows the menu bar too */
@media (prefers-color-scheme: light) {
  body { color: black; }
}

تقليل الحركة

عند تشغيل تقليل الحركة، تكون reduceMotion هي true ويتطابق prefers-reduced-motion. أبقِ المؤشر مقروءًا وتخلَّ عن الارتدادات والنبضات والمسحات:

body.reduce-motion * { transition: none !important; animation: none !important; }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

أمثلة كاملة

واجهتان كاملتان تعملان مباشرة في هذه الصفحة عبر البيانات نفسها التي يرسلها Multimeter. انسخ الملفات إلى مجلد واستورده.

واجهة البداية من إنشاء واجهة

ما يكتبه إنشاء واجهة… بالضبط: تسمية، وشريط، والقيمة المنسقة، مع شرح الواجهة البرمجية في تعليقاتها. تلوّن نفسها حسب state، وتحترم tint، وتتبع مظهر شريط القوائم.

starter/manifest.json

{
  "name": "My Face",
  "description": "A label, a bar and the value. Works with any source.",
  "version": "1.0.0",
  "author": "Your Name",
  "apiVersion": 2,
  "sources": ["any"],
  "defaultSource": "cpu",
  "width": 70,
  "minWidth": 50,
  "maxWidth": 120,
  "supportsLightMode": true,
  "supportsDarkMode": true
}

starter/index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div id="meter">
        <span id="label"></span>
        <span id="track"><span id="fill"></span></span>
        <span id="value">--</span>
    </div>
    <script src="meter.js"></script>
</body>
</html>

starter/styles.css

* { margin: 0; padding: 0; box-sizing: border-box; }

/* The meter is 22 points tall and as wide as manifest.json says. */
body {
    font: 600 11px/1 -apple-system, BlinkMacSystemFont, sans-serif;
    font-variant-numeric: tabular-nums;
    color: white;                 /* dark menu bar */
    background: transparent;
    height: 22px;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    --accent: #30d158;            /* replaced by the meter's color, if one is set */
}

/* Light menu bar: the system setting, or the preview's light mode. */
#track { background: rgba(255, 255, 255, 0.25); }
@media (prefers-color-scheme: light) { body { color: black; } #track { background: rgba(0, 0, 0, 0.18); } }
body.light-mode { color: black; }
body.light-mode #track { background: rgba(0, 0, 0, 0.18); }
body.dark-mode { color: white; }
body.dark-mode #track { background: rgba(255, 255, 255, 0.25); }

#meter { display: flex; align-items: center; gap: 4px; }
#label { font-size: 8px; letter-spacing: 0.04em; opacity: 0.7; }
#track { width: 18px; height: 6px; border-radius: 3px; position: relative; overflow: hidden; }
#fill { position: absolute; inset: 0 auto 0 0; width: 0; background: var(--accent); border-radius: 3px; transition: width 0.4s ease; }

/* state is "normal", "warning" or "critical" (from the meter's alert levels). */
body.warning { --accent: #ffd60a; }
body.critical { --accent: #ff453a; }

@media (prefers-reduced-motion: reduce) { #fill { transition: none; } }

starter/meter.js

// Multimeter meter API, version 2. The app sets window.meterData and fires
// a 'meterUpdate' event whenever anything changes. The fields you'll use most:
//
//   level        0.0 to 1.0, the value within the meter's range
//   formatted    ready-to-show text with its unit: "23%", "1.2 MB/s", "4:12"
//   label        short label ("CPU"), may be "" if hidden
//   value, unit, min, max   the raw number and its range
//   state        "normal", "warning" or "critical"
//   tint         the color picked in Customize ("#30D158"), or null
//   history      up to 60 recent levels (0 to 1), oldest first, for graphs
//   source       what it measures: "battery", "cpu", "memory", "network", "timer"...
//   available    false when there's nothing to read (no battery, URL failing)
//   battery      the Mac's battery, always: level, isCharging, isPluggedIn,
//                hasBattery, timeRemaining, timeToFullCharge, health...
//   isCharging   true only when this meter shows the battery and it's charging
//   colorScheme  "light" or "dark"; reduceMotion  true if animations should stop
//
// Full reference: https://multimeterapp.com/creating-meters

class Meter {
    constructor() {
        this.label = document.getElementById('label');
        this.fill = document.getElementById('fill');
        this.value = document.getElementById('value');
        window.addEventListener('meterUpdate', (e) => this.render(e.detail));
        if (window.meterData) this.render(window.meterData);
        window.meterReady = true;
    }

    render(data) {
        const level = Math.max(0, Math.min(1, data.level || 0));
        this.label.textContent = data.label || '';
        this.label.style.display = data.label ? '' : 'none';
        this.value.textContent = data.available === false ? '\u2013' : (data.formatted || Math.round(level * 100) + '%');
        this.fill.style.width = (level * 100) + '%';

        document.body.classList.toggle('warning', data.state === 'warning');
        document.body.classList.toggle('critical', data.state === 'critical');
        if (data.tint) document.body.style.setProperty('--accent', data.tint);
        else document.body.style.removeProperty('--accent');
    }
}

if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => new Meter());
} else {
    new Meter();
}

رسم السجل

رسم خطي لآخر دقيقة من history، مرسوم على canvas بدقة الشاشة الحقيقية.

history-graph/manifest.json

{
  "name": "History Graph",
  "description": "The last minute as a little line graph.",
  "version": "1.0.0",
  "author": "Your Name",
  "apiVersion": 2,
  "sources": ["any"],
  "defaultSource": "network",
  "width": 44,
  "minWidth": 30,
  "maxWidth": 80,
  "supportsLightMode": true,
  "supportsDarkMode": true
}

history-graph/index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <style>
    html, body { margin: 0; height: 22px; background: transparent; overflow: hidden; }
    canvas { display: block; width: 100%; height: 22px; }
  </style>
</head>
<body>
  <canvas id="graph"></canvas>
  <script src="meter.js"></script>
</body>
</html>

history-graph/meter.js

const canvas = document.getElementById('graph');
const ctx = canvas.getContext('2d');

function render(data) {
  // Draw at the screen's real resolution so the line stays sharp
  const scale = window.devicePixelRatio || 1;
  const w = canvas.clientWidth, h = 22;
  canvas.width = w * scale;
  canvas.height = h * scale;
  ctx.setTransform(scale, 0, 0, scale, 0, 0);
  ctx.clearRect(0, 0, w, h);

  const points = (data.history || []).concat(data.level ?? 0);
  if (points.length < 2) return;

  const dark = data.colorScheme !== 'light';
  const color = data.tint
    || (data.state === 'critical' ? '#ff453a' : data.state === 'warning' ? '#ff9f0a' : dark ? '#fff' : '#1d1d1f');
  const x = (i) => (i / (points.length - 1)) * (w - 2) + 1;
  const y = (v) => h - 3 - v * (h - 6);

  // Soft fill under the line, then the line
  ctx.beginPath();
  points.forEach((v, i) => (i ? ctx.lineTo(x(i), y(v)) : ctx.moveTo(x(i), y(v))));
  ctx.lineTo(x(points.length - 1), h);
  ctx.lineTo(x(0), h);
  ctx.closePath();
  ctx.globalAlpha = 0.22;
  ctx.fillStyle = color;
  ctx.fill();

  ctx.globalAlpha = 1;
  ctx.beginPath();
  points.forEach((v, i) => (i ? ctx.lineTo(x(i), y(v)) : ctx.moveTo(x(i), y(v))));
  ctx.strokeStyle = color;
  ctx.lineWidth = 1.5;
  ctx.lineJoin = 'round';
  ctx.stroke();
}

window.addEventListener('meterUpdate', (e) => render(e.detail));
render(window.meterData || { history: [0.2, 0.4, 0.3, 0.6, 0.5], level: 0.7 });
window.meterReady = true;

نصائح للاختبار

  • أبقِ كل شيء ضمن ارتفاع 22 نقطة، وافحص واجهتك عند minWidth وmaxWidth.
  • استخدم خط النظام (-apple-system) وfont-variant-numeric: tabular-nums حتى لا تهتز الأرقام.
  • جرّب واجهتك مع عدة مصادر في إضافة مؤشر… وتخصيص هذا المؤشر…: نسبة مئوية، وسرعة الشبكة، ومؤقت، ومصدر غير متاح.
  • افحص شريط القوائم الفاتح والداكن، ولونًا مخصصًا، وحالتي التحذير والحرج.
  • تظهر أخطاء JavaScript في Console.app. يمكنك أيضًا فتح index.html في Safari وإرسال البيانات إليه من وحدة التحكم:
  • أبقِ الملفات صغيرة وتجنّب طلبات الشبكة، حتى تُرسم الواجهة فورًا.
// Paste in Safari's console with your index.html open to try a value
window.meterData = { level: 0.92, formatted: '92%', label: 'CPU', state: 'critical',
  available: true, colorScheme: 'dark', history: [] };
window.dispatchEvent(new CustomEvent('meterUpdate', { detail: window.meterData }));

مستعد للإنشاء؟

$19.99 دفعة واحدة. بلا اشتراك. استرداد خلال 30 يومًا.

اشترِ مقابل $19.99