|
| 1 | +# Calendar Widget Options |
| 2 | + |
| 3 | +Shows the next upcoming Google Calendar event in the bar. Left-click joins the meeting (Google Meet, Zoom, or Microsoft Teams) by opening the join URL in the default browser. |
| 4 | + |
| 5 | +| Option | Type | Default | Description | |
| 6 | +|-------------------------|---------|----------------------------------------------------------------------|-------------| |
| 7 | +| `label` | string | `'{icon} {title} {countdown}'` | Format string for the bar label. Tokens: `{icon}`, `{title}`, `{start_time}`, `{countdown}`, `{status}`, `{meeting_kind}`. | |
| 8 | +| `label_alt` | string | `'{icon} {title} at {start_time}'` | Alternative label, swapped via `toggle_label`. | |
| 9 | +| `class_name` | string | `''` | Extra CSS class appended to the widget frame. | |
| 10 | +| `update_interval` | integer | `60` | Seconds between Google Calendar API polls. Range 15–3600. | |
| 11 | +| `tick_interval` | integer | `1000` | Milliseconds between countdown re-renders (no API call). Range 250–60000. | |
| 12 | +| `calendar_ids` | list of strings | `['primary']` | Calendar IDs to read. Events from all listed calendars are merged and sorted by start time. Use `primary`, another email, or any calendar ID from your Google Calendar settings. | |
| 13 | +| `credentials_path` | string | `'~/.config/yasb/calendar/credentials.json'` | Path to the OAuth client JSON downloaded from Google Cloud Console. | |
| 14 | +| `token_path` | string | `'~/.config/yasb/calendar/token.json'` | Where the refresh token is cached after first authorisation. | |
| 15 | +| `look_ahead_minutes` | integer | `0` | If > 0, only show events starting within this many minutes. `0` = always show the next event regardless of how far away. | |
| 16 | +| `grace_period_minutes` | integer | `5` | Keep showing an in-progress event until this many minutes after its start. Range 0–120. | |
| 17 | +| `skip_all_day` | boolean | `true` | Skip all-day events when picking the "next" event. | |
| 18 | +| `max_title_length` | integer | `30` | Truncate event titles longer than this. | |
| 19 | +| `tooltip_event_count` | integer | `3` | Number of upcoming events to show in the hover tooltip. The bar label always shows just the next one. Range 1–10. | |
| 20 | +| `hide_when_empty` | boolean | `true` | Hide the widget when there are no upcoming events; otherwise show `empty_label`. | |
| 21 | +| `empty_label` | string | `'No upcoming events'` | Shown when there is no upcoming event (only if `hide_when_empty` is false). | |
| 22 | +| `auth_label` | string | `'Calendar: setup needed'` | Shown when `credentials.json` is missing. Click to open the setup docs. | |
| 23 | +| `setup_url` | string | `'https://github.com/amnweb/yasb/blob/main/docs/widgets/calendar.md'` | URL opened by `open_setup`. | |
| 24 | +| `tooltip` | boolean | `true` | Show a tooltip on hover with full title, time range, and location. | |
| 25 | +| `icons` | dict | `{'meet': '', 'zoom': '', 'teams': '', 'other': '', 'none': '', 'calendar': ''}` | Per-platform icon glyphs. Set to whichever Nerd Font codepoints you prefer. | |
| 26 | +| `callbacks` | dict | `{'on_left': 'join_meeting', 'on_middle': 'open_event', 'on_right': 'toggle_label'}` | Mouse callbacks. See *Callbacks* below. | |
| 27 | + |
| 28 | +## Example Configuration |
| 29 | + |
| 30 | +```yaml |
| 31 | +calendar: |
| 32 | + type: "yasb.calendar.CalendarWidget" |
| 33 | + options: |
| 34 | + label: "<span class=\"icon\">{icon}</span> {title} {countdown}" |
| 35 | + label_alt: "<span class=\"icon\">{icon}</span> {title} at {start_time}" |
| 36 | + update_interval: 60 |
| 37 | + tick_interval: 1000 |
| 38 | + calendar_ids: |
| 39 | + - "primary" |
| 40 | + - "you@example.com" |
| 41 | + look_ahead_minutes: 120 |
| 42 | + grace_period_minutes: 5 |
| 43 | + skip_all_day: true |
| 44 | + max_title_length: 30 |
| 45 | + tooltip_event_count: 3 |
| 46 | + hide_when_empty: true |
| 47 | + icons: |
| 48 | + meet: "" |
| 49 | + zoom: "" |
| 50 | + teams: "" |
| 51 | + other: "" |
| 52 | + none: "" |
| 53 | + calendar: "" |
| 54 | + callbacks: |
| 55 | + on_left: "join_meeting" |
| 56 | + on_middle: "open_event" |
| 57 | + on_right: "toggle_label" |
| 58 | +``` |
| 59 | +
|
| 60 | +## One-time Google Calendar Setup |
| 61 | +
|
| 62 | +The widget reads your calendar via the Google Calendar API. You only have to do this once. |
| 63 | +
|
| 64 | +1. Open the [Google Cloud Console](https://console.cloud.google.com/) and create (or pick) a project. |
| 65 | +2. Enable the **Google Calendar API** for that project (APIs & Services → Library). |
| 66 | +3. Configure the OAuth consent screen as **External**, add your own Google account as a test user, and set scope `https://www.googleapis.com/auth/calendar.readonly`. |
| 67 | +4. Create credentials → **OAuth client ID** → application type **Desktop app**. Download the JSON file. |
| 68 | +5. Save it as `%USERPROFILE%\.config\yasb\calendar\credentials.json` (or set `credentials_path` to wherever you put it). |
| 69 | +6. Start YASB. The first time the widget runs it opens a browser tab asking you to authorise read-only access to your calendar. After you accept, a refresh token is cached at `token_path` and no further prompts are needed. |
| 70 | + |
| 71 | +The token only grants read access. To revoke it, delete `token.json` and remove the app from <https://myaccount.google.com/permissions>. |
| 72 | + |
| 73 | +## Tokens |
| 74 | + |
| 75 | +Tokens you can use in `label` / `label_alt`: |
| 76 | + |
| 77 | +- `{icon}` — picked from `icons` based on the meeting platform (`meet`/`zoom`/`teams`/`other`/`none`). |
| 78 | +- `{title}` — event title, truncated to `max_title_length`. |
| 79 | +- `{start_time}` — local time of the event start in `HH:MM`. |
| 80 | +- `{countdown}` — `in 12m`, `in 1h 20m`, `now`, `started 3m ago`. |
| 81 | +- `{status}` — `upcoming`, `live`, `ended` (also applied as a CSS class). |
| 82 | +- `{meeting_kind}` — `meet`, `zoom`, `teams`, `other`, or `none`. |
| 83 | + |
| 84 | +## Callbacks |
| 85 | + |
| 86 | +| Name | Behaviour | |
| 87 | +|----------------|-----------| |
| 88 | +| `join_meeting` | Open the meeting join URL in the default browser. Falls back to the calendar event page if no URL is found. If credentials are missing, opens `setup_url` instead. | |
| 89 | +| `open_event` | Open the event's `htmlLink` (Google Calendar web view). | |
| 90 | +| `toggle_label` | Swap between `label` and `label_alt`. | |
| 91 | +| `refresh` | Force a re-poll of the API (skipped if a poll is already in flight). | |
| 92 | +| `open_setup` | Open `setup_url`. | |
| 93 | + |
| 94 | +## How the meeting URL is detected |
| 95 | + |
| 96 | +In priority order: |
| 97 | + |
| 98 | +1. `event.hangoutLink` — Google Meet links auto-attached to the event. |
| 99 | +2. `event.conferenceData.entryPoints[]` — first entry with `entryPointType: video`. Classified by host (`zoom.us`, `teams.microsoft.com`, etc.). |
| 100 | +3. Regex over the event's `location` and `description` for `https://*.zoom.us/...`, `https://teams.microsoft.com/l/meetup-join/...`, or `https://meet.google.com/xxx-xxxx-xxx`. |
| 101 | + |
| 102 | +If nothing matches, `join_meeting` falls back to opening the event in Google Calendar. |
| 103 | + |
| 104 | +## Style example |
| 105 | + |
| 106 | +The widget frame gets state classes you can target from `styles.css`: |
| 107 | + |
| 108 | +```css |
| 109 | +.calendar-widget { |
| 110 | + padding: 0 8px; |
| 111 | +} |
| 112 | +.calendar-widget.live { |
| 113 | + color: #f5a; |
| 114 | + font-weight: 600; |
| 115 | +} |
| 116 | +.calendar-widget.upcoming.meet { |
| 117 | + color: #00897b; |
| 118 | +} |
| 119 | +.calendar-widget.zoom { color: #2d8cff; } |
| 120 | +.calendar-widget.teams { color: #6264a7; } |
| 121 | +.calendar-widget.setup, |
| 122 | +.calendar-widget.error { |
| 123 | + color: #ff8a65; |
| 124 | +} |
| 125 | +``` |
| 126 | + |
| 127 | +State classes added to the frame: one of `loading`, `ok`, `empty`, `setup`, `error`, plus when state is `ok`: the meeting kind (`meet`/`zoom`/`teams`/`other`/`none`) and the status (`upcoming`/`live`/`ended`). |
0 commit comments