ggbro Plugins

Hello Sample

com.ggbro.sample.hello · v3.0.0 · ui.toast, theme.read, app.info, ui.panel, ui.sound, storage

Polished starter — nickname, vibe picker, visit progress, sounds, and live theme readout.

Sandbox example — full pack source. Everything below runs in the plugin iframe via window.ggbro. This is the complete plugin.

manifest.json

Raw
{
  "id": "com.ggbro.sample.hello",
  "name": "Hello Sample",
  "version": "3.0.0",
  "author": "ggbro",
  "description": "Polished starter — nickname, vibe picker, visit progress, sounds, and live theme readout.",
  "main": "plugin.js",
  "styles": "styles.css",
  "permissions": ["ui.toast", "theme.read", "app.info", "ui.panel", "ui.sound", "storage"]
}

plugin.js

Raw
/**
 * Hello Sample v3 — polished starter using the full panel toolkit.
 */
(async function () {
  var visits = 0;
  var version = '?';
  var accent = '';
  var displayName = 'friend';
  var vibe = 'friendly';

  try {
    visits = parseInt((await ggbro.storage.get('visits')).value || '0', 10) || 0;
    visits += 1;
    await ggbro.storage.set('visits', String(visits));
    displayName = (await ggbro.storage.get('displayName')).value || 'friend';
    vibe = (await ggbro.storage.get('vibe')).value || 'friendly';
    if (['friendly', 'hype', 'chill'].indexOf(vibe) < 0) vibe = 'friendly';
  } catch (e) {
    ggbro.log('storage', e && e.message);
  }

  try {
    var info = await ggbro.getAppInfo();
    version = (info && info.version) || '?';
  } catch (e) {
    ggbro.log('appinfo', e && e.message);
  }

  try {
    var theme = await ggbro.getTheme();
    accent = (theme && (theme.accent || theme.accentPreset)) || '';
  } catch (e) {
    ggbro.log('theme', e && e.message);
  }

  function greetLine() {
    var lines = {
      friendly: 'Hello, ' + displayName + ' — glad you’re here.',
      hype: 'Let’s go, ' + displayName + ' — main character energy.',
      chill: 'Hey ' + displayName + ' — settle in, no rush.',
    };
    return lines[vibe] || lines.friendly;
  }

  async function paintPanel() {
    await ggbro.ui.registerPanel({
      id: 'main',
      title: 'Hello Sample',
      schema: [
        {
          type: 'notice',
          id: 'tip',
          text: 'Starter pack — rename yourself, pick a vibe, then try the buttons. Docs: ggbro.app/developers/plugins',
          tone: 'info',
        },
        { type: 'section', id: 's0', title: 'Status' },
        { type: 'text', id: 'ver', label: 'Desktop', value: 'v' + version },
        { type: 'text', id: 'accent', label: 'Accent', value: accent || '—' },
        { type: 'progress', id: 'visitsBar', label: 'Visits (capped preview)', value: Math.min(visits, 20), max: 20 },
        { type: 'text', id: 'visits', label: 'Visits on this PC', value: String(visits) },
        { type: 'section', id: 's1', title: 'Personalize' },
        {
          type: 'input',
          id: 'name',
          label: 'Call me',
          value: displayName,
          placeholder: 'Your nickname',
        },
        {
          type: 'select',
          id: 'vibe',
          label: 'Greeting vibe',
          value: vibe,
          options: [
            { value: 'friendly', label: 'Friendly' },
            { value: 'hype', label: 'Hype' },
            { value: 'chill', label: 'Chill' },
          ],
        },
        { type: 'section', id: 's2', title: 'Try it' },
        { type: 'button', id: 'greet', label: 'Say hello' },
        { type: 'button', id: 'ding', label: 'Play sound' },
        { type: 'button', id: 'reset', label: 'Reset visit counter' },
        { type: 'link', id: 'docs', label: 'Plugin docs', href: 'https://ggbro.app/developers/plugins' },
      ],
    });
  }

  await paintPanel();
  await ggbro.toast({
    message: greetLine() + ' Open Settings → Plugins for controls.',
    type: 'success',
  });

  ggbro.onThemeChange(function (theme) {
    accent = (theme && (theme.accent || theme.accentPreset)) || '';
    paintPanel().catch(function () {});
  });

  ggbro.onEvent(function (event, payload) {
    if (event !== 'panelAction' || !payload) return;
    if (payload.fieldId === 'name') {
      displayName = String(payload.value || 'friend').trim().slice(0, 32) || 'friend';
      ggbro.storage.set('displayName', displayName).catch(function () {});
      paintPanel();
      ggbro.toast({ message: 'Got it — hello, ' + displayName + '!', type: 'success' });
      return;
    }
    if (payload.fieldId === 'vibe') {
      vibe = String(payload.value || 'friendly');
      if (['friendly', 'hype', 'chill'].indexOf(vibe) < 0) vibe = 'friendly';
      ggbro.storage.set('vibe', vibe).catch(function () {});
      paintPanel();
      return;
    }
    if (payload.fieldId === 'greet') {
      ggbro.toast({
        message: greetLine() + ' · visit #' + visits + ' · v' + version,
        type: 'success',
      });
      return;
    }
    if (payload.fieldId === 'ding') {
      ggbro.playSound({ id: 'boing' }).catch(function () {});
      ggbro.toast({ message: 'Boing!', type: 'info' });
      return;
    }
    if (payload.fieldId === 'reset') {
      visits = 0;
      ggbro.storage.set('visits', '0').then(function () {
        return paintPanel();
      }).then(function () {
        return ggbro.toast({ message: 'Visit counter reset', type: 'warning' });
      });
    }
  });
})();

styles.css

Raw
/* Custom properties only — host sanitizer keeps :root/html/body --vars. */
:root {
  --ggbro-plugin-hello: 1;
}

README.md

Raw
# Hello Sample (v2)

Official starter for the host-rendered panel API.

- **Settings → Plugins** panel with Say hello / Play sound / Reset counter
- Visit counter via `storage`
- Live accent readout via `theme.read`

Download the `.ggbro-plugin` pack from the docs examples page.