ggbro Plugins

Startup Greeting

com.ggbro.plugin.startup-greeting · v3.0.0 · ui.toast, app.info, ui.panel, ui.sound, storage

Welcome panel — optional name, vibe styles, live preview notice, and greeting progress.

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.plugin.startup-greeting",
  "name": "Startup Greeting",
  "version": "3.0.0",
  "author": "ggbro",
  "description": "Welcome panel — optional name, vibe styles, live preview notice, and greeting progress.",
  "main": "plugin.js",
  "styles": "styles.css",
  "permissions": ["ui.toast", "app.info", "ui.panel", "ui.sound", "storage"]
}

plugin.js

Raw
/**
 * Startup Greeting v3 — custom name, notice preview, richer vibes.
 */
(async function () {
  var style = 'warm';
  var soundOn = true;
  var version = '';
  var lastMsg = '';
  var greetCount = 0;
  var displayName = '';

  var vibes = {
    warm: [
      'Let’s make something cool today.',
      'Glad you’re here.',
      'One message at a time.',
    ],
    hype: [
      'Stay legendary.',
      'Voice on, chaos optional.',
      'Main character energy.',
    ],
    chill: [
      'No rush — settle in.',
      'Your servers miss you (probably).',
      'Breathe. Then chat.',
    ],
  };

  try {
    var saved = (await ggbro.storage.get('style')).value;
    if (saved === 'warm' || saved === 'hype' || saved === 'chill') style = saved;
    soundOn = ((await ggbro.storage.get('soundOn')).value || '1') !== '0';
    greetCount = parseInt((await ggbro.storage.get('greets')).value || '0', 10) || 0;
    lastMsg = (await ggbro.storage.get('lastMsg')).value || '';
    displayName = (await ggbro.storage.get('displayName')).value || '';
  } catch (e) {
    ggbro.log('storage', e && e.message);
  }

  try {
    var info = await ggbro.getAppInfo();
    version = info && info.version ? String(info.version) : '';
  } catch (err) {
    ggbro.log('getAppInfo', err && err.message);
  }

  function helloWord() {
    var hour = new Date().getHours();
    if (hour < 5) return 'Still up?';
    if (hour < 12) return 'Good morning';
    if (hour < 17) return 'Good afternoon';
    if (hour < 21) return 'Good evening';
    return 'Burning the midnight oil?';
  }

  function buildMsg() {
    var list = vibes[style] || vibes.warm;
    var vibe = list[Math.floor(Math.random() * list.length)];
    var who = displayName ? ', ' + displayName : '';
    return helloWord() + who + (version ? ' — desktop v' + version : '') + '. ' + vibe;
  }

  async function paint() {
    await ggbro.ui.registerPanel({
      id: 'greet',
      title: 'Startup Greeting',
      schema: [
        {
          type: 'notice',
          id: 'preview',
          text: lastMsg || 'Press “Greet me again” for a fresh welcome.',
          tone: 'success',
        },
        { type: 'section', id: 's0', title: 'Stats' },
        { type: 'progress', id: 'gbar', label: 'Greetings played', value: Math.min(greetCount, 25), max: 25 },
        { type: 'text', id: 'count', label: 'Total greetings', value: String(greetCount) },
        { type: 'section', id: 's1', title: 'Style' },
        {
          type: 'input',
          id: 'name',
          label: 'Your name (optional)',
          value: displayName,
          placeholder: 'Shown in greetings',
        },
        {
          type: 'select',
          id: 'style',
          label: 'Vibe',
          value: style,
          options: [
            { value: 'warm', label: 'Warm' },
            { value: 'hype', label: 'Hype' },
            { value: 'chill', label: 'Chill' },
          ],
        },
        { type: 'toggle', id: 'sound', label: 'Play sound with greeting', value: soundOn },
        { type: 'button', id: 'replay', label: 'Greet me again' },
      ],
    });
  }

  async function greet(silentToast) {
    lastMsg = buildMsg();
    greetCount += 1;
    try {
      await ggbro.storage.set('lastMsg', lastMsg.slice(0, 200));
      await ggbro.storage.set('greets', String(greetCount));
    } catch (e) {}
    if (soundOn) ggbro.playSound({ id: 'notification' }).catch(function () {});
    if (!silentToast) {
      await ggbro.toast({ message: lastMsg, type: 'success' });
    }
    await paint();
  }

  await paint();
  await greet(false);

  ggbro.onEvent(function (event, payload) {
    if (event !== 'panelAction' || !payload) return;
    if (payload.fieldId === 'name') {
      displayName = String(payload.value || '').trim().slice(0, 32);
      ggbro.storage.set('displayName', displayName).catch(function () {});
      paint();
      ggbro.toast({
        message: displayName ? 'Name set to ' + displayName : 'Name cleared',
        type: 'info',
      });
      return;
    }
    if (payload.fieldId === 'style') {
      var v = String(payload.value || 'warm');
      if (v === 'warm' || v === 'hype' || v === 'chill') {
        style = v;
        ggbro.storage.set('style', style).catch(function () {});
        ggbro.toast({ message: 'Vibe set to ' + style, type: 'info' });
      }
      return;
    }
    if (payload.fieldId === 'sound') {
      soundOn = !!payload.value;
      ggbro.storage.set('soundOn', soundOn ? '1' : '0').catch(function () {});
      return;
    }
    if (payload.fieldId === 'replay') {
      greet(false);
    }
  });
})();

styles.css

Raw
:root {
  --ggbro-plugin-startup-greeting: 1;
}

README.md

Raw
# Startup Greeting (v2)

Welcome panel with vibe style (warm / hype / chill), sound toggle, and **Greet me again**.