|
| 1 | +<!doctype html> |
| 2 | +<html lang="en"> |
| 3 | +<head> |
| 4 | + <meta charset="UTF-8" /> |
| 5 | + <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| 6 | + <title>ote-events — embeddable OTE events widget</title> |
| 7 | + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@highlightjs/cdn-assets@11.11.1/styles/github-dark.min.css" /> |
| 8 | + <link rel="stylesheet" href="./styles.css" /> |
| 9 | +</head> |
| 10 | +<body> |
| 11 | + <header> |
| 12 | + <h1><ote-events></h1> |
| 13 | + <p> |
| 14 | + A single Web Component that renders upcoming events from any |
| 15 | + <a href="https://github.com/OpenTechEvents/opentechevents-spec" target="_blank" rel="noopener">OTE</a> |
| 16 | + JSON feed. No framework, no build step, no package to install — one |
| 17 | + <code><script></code> tag and one element. This page doubles as |
| 18 | + its documentation: every control below maps to one HTML attribute, and |
| 19 | + the snippet at the bottom always reflects exactly what you're seeing. |
| 20 | + </p> |
| 21 | + </header> |
| 22 | + |
| 23 | + <main class="playground-layout"> |
| 24 | + <div class="controls-column"> |
| 25 | + <section class="panel controls" aria-labelledby="controls-heading"> |
| 26 | + <h2 id="controls-heading">Try it</h2> |
| 27 | + |
| 28 | + <div class="field"> |
| 29 | + <span class="fields-legend">data source</span> |
| 30 | + <div class="source-options"> |
| 31 | + <label><input type="radio" name="source-mode" value="url" checked /> feed URL</label> |
| 32 | + <label><input type="radio" name="source-mode" value="json" /> manual JSON</label> |
| 33 | + </div> |
| 34 | + </div> |
| 35 | + |
| 36 | + <div class="field" id="feed-source-field"> |
| 37 | + <label for="feed-input">feed</label> |
| 38 | + <input type="url" id="feed-input" value="https://combuilderses.github.io/events/feed.json" /> |
| 39 | + <p class="hint">The URL of an OTE <code>feed.json</code> document.</p> |
| 40 | + </div> |
| 41 | + |
| 42 | + <div class="field" id="json-source-field" hidden> |
| 43 | + <label for="feed-data-input">feedData / event JSON</label> |
| 44 | + <textarea id="feed-data-input" rows="9" spellcheck="false" disabled placeholder='{"events":[{"name":"Runtime event","startDate":"2999-01-01"}]}'></textarea> |
| 45 | + <p class="hint">Paste an OTE feed object, an event array, or one OTE event object.</p> |
| 46 | + </div> |
| 47 | + |
| 48 | + <div class="field"> |
| 49 | + <label for="limit-input">limit</label> |
| 50 | + <input type="number" id="limit-input" min="1" step="1" placeholder="No limit" /> |
| 51 | + <p class="hint">Optional maximum number of events to show. Default: no limit.</p> |
| 52 | + </div> |
| 53 | + |
| 54 | + <div class="field"> |
| 55 | + <label for="placeholder-image-input">placeholder-image override</label> |
| 56 | + <input type="url" id="placeholder-image-input" placeholder="Optional image URL for cards without images" /> |
| 57 | + <p class="hint">Optional. Cards use a built-in placeholder when an event has no image.</p> |
| 58 | + </div> |
| 59 | + |
| 60 | + <div class="field"> |
| 61 | + <label for="event-click-select">event-click</label> |
| 62 | + <select id="event-click-select"> |
| 63 | + <option value="modal" selected>modal</option> |
| 64 | + <option value="link">link</option> |
| 65 | + <option value="none">none</option> |
| 66 | + </select> |
| 67 | + <p class="hint">What happens when a visitor selects an event. Default: modal.</p> |
| 68 | + </div> |
| 69 | + |
| 70 | + <div class="field"> |
| 71 | + <span class="fields-legend">event-actions</span> |
| 72 | + <div class="fields-checkboxes"> |
| 73 | + <label><input type="checkbox" class="event-action-checkbox" value="google-calendar" checked /> Google Calendar</label> |
| 74 | + <label><input type="checkbox" class="event-action-checkbox" value="outlook-calendar" checked /> Outlook</label> |
| 75 | + <label><input type="checkbox" class="event-action-checkbox" value="yahoo-calendar" checked /> Yahoo</label> |
| 76 | + <label><input type="checkbox" class="event-action-checkbox" value="ics" checked /> ICS</label> |
| 77 | + <label><input type="checkbox" class="event-action-checkbox" value="link" checked /> event page</label> |
| 78 | + </div> |
| 79 | + <p class="hint">Actions shown inside the event detail view. Default: all checked.</p> |
| 80 | + </div> |
| 81 | + |
| 82 | + <div class="field custom-action-demo"> |
| 83 | + <label for="custom-action-checkbox"> |
| 84 | + <input type="checkbox" id="custom-action-checkbox" /> |
| 85 | + custom button example |
| 86 | + </label> |
| 87 | + <div class="custom-action-options"> |
| 88 | + <label for="custom-action-placement-select">placement</label> |
| 89 | + <select id="custom-action-placement-select"> |
| 90 | + <option value="preview">preview</option> |
| 91 | + <option value="detail">detail</option> |
| 92 | + <option value="both" selected>both</option> |
| 93 | + </select> |
| 94 | + </div> |
| 95 | + <p class="hint">Adds a custom action with an icon that shows an alert for the selected event.</p> |
| 96 | + </div> |
| 97 | + |
| 98 | + <div class="field"> |
| 99 | + <label for="font-family-input">font-family</label> |
| 100 | + <input type="text" id="font-family-input" placeholder='system default, Inter, "Segoe UI", sans-serif' /> |
| 101 | + <p class="hint">Optional CSS font-family for the widget.</p> |
| 102 | + </div> |
| 103 | + |
| 104 | + <div class="field"> |
| 105 | + <label for="font-size-input">font-size</label> |
| 106 | + <input type="text" id="font-size-input" placeholder="1rem, 16px, 0.95em..." /> |
| 107 | + <p class="hint">Optional base font-size for the widget.</p> |
| 108 | + </div> |
| 109 | + |
| 110 | + <div class="field"> |
| 111 | + <span class="fields-legend">fields</span> |
| 112 | + <div class="fields-checkboxes"> |
| 113 | + <label><input type="checkbox" class="field-key-checkbox" value="image" checked /> image</label> |
| 114 | + <label><input type="checkbox" class="field-key-checkbox" value="when" checked /> when</label> |
| 115 | + <label><input type="checkbox" class="field-key-checkbox" value="location" checked /> location</label> |
| 116 | + <label><input type="checkbox" class="field-key-checkbox" value="attendance" checked /> attendance</label> |
| 117 | + <label><input type="checkbox" class="field-key-checkbox" value="description" checked /> description</label> |
| 118 | + <label><input type="checkbox" class="field-key-checkbox" value="price" /> price</label> |
| 119 | + <label><input type="checkbox" class="field-key-checkbox" value="tags" /> tags</label> |
| 120 | + <label><input type="checkbox" class="field-key-checkbox" value="organizer" /> organizer</label> |
| 121 | + </div> |
| 122 | + <p class="hint">Which optional pieces of each event to show. Ignored by the calendar layout.</p> |
| 123 | + </div> |
| 124 | + |
| 125 | + <div class="field"> |
| 126 | + <label for="lang-select">lang</label> |
| 127 | + <select id="lang-select"> |
| 128 | + <option value="auto" selected>auto</option> |
| 129 | + <option value="en">en</option> |
| 130 | + <option value="es">es</option> |
| 131 | + </select> |
| 132 | + <p class="hint">Language of the widget's own UI text (loading/empty/error messages). "auto" follows the visitor's browser language.</p> |
| 133 | + </div> |
| 134 | + |
| 135 | + <div class="field field-checkbox"> |
| 136 | + <label for="show-past-checkbox"> |
| 137 | + <input type="checkbox" id="show-past-checkbox" checked /> |
| 138 | + show-past |
| 139 | + </label> |
| 140 | + <p class="hint">Include events whose start date has already passed. Default: on.</p> |
| 141 | + </div> |
| 142 | + </section> |
| 143 | + </div> |
| 144 | + |
| 145 | + <div class="output-column"> |
| 146 | + <section class="panel" aria-labelledby="preview-heading"> |
| 147 | + <h2 id="preview-heading">Live preview</h2> |
| 148 | + <div class="preview-toolbar"> |
| 149 | + <div class="segmented-toolbar" role="group" aria-label="Preview layout"> |
| 150 | + <button type="button" class="preview-button" data-layout="calendar" aria-pressed="true" title="Calendar layout"> |
| 151 | + <span class="preview-icon icon-calendar" aria-hidden="true"></span> |
| 152 | + <span>Calendar</span> |
| 153 | + </button> |
| 154 | + <button type="button" class="preview-button" data-layout="list" aria-pressed="false" title="List layout"> |
| 155 | + <span class="preview-icon icon-list" aria-hidden="true"></span> |
| 156 | + <span>List</span> |
| 157 | + </button> |
| 158 | + <button type="button" class="preview-button" data-layout="cards" aria-pressed="false" title="Cards layout"> |
| 159 | + <span class="preview-icon icon-cards" aria-hidden="true"></span> |
| 160 | + <span>Cards</span> |
| 161 | + </button> |
| 162 | + </div> |
| 163 | + <div class="segmented-toolbar" role="group" aria-label="Preview theme"> |
| 164 | + <button type="button" class="preview-button" data-theme="auto" aria-pressed="true" title="Auto theme"> |
| 165 | + <span class="preview-icon icon-auto" aria-hidden="true"></span> |
| 166 | + <span>Auto</span> |
| 167 | + </button> |
| 168 | + <button type="button" class="preview-button" data-theme="light" aria-pressed="false" title="Light theme"> |
| 169 | + <span class="preview-icon icon-light" aria-hidden="true"></span> |
| 170 | + <span>Light</span> |
| 171 | + </button> |
| 172 | + <button type="button" class="preview-button" data-theme="dark" aria-pressed="false" title="Dark theme"> |
| 173 | + <span class="preview-icon icon-dark" aria-hidden="true"></span> |
| 174 | + <span>Dark</span> |
| 175 | + </button> |
| 176 | + </div> |
| 177 | + </div> |
| 178 | + <div class="widget-frame"> |
| 179 | + <ote-events id="preview-widget" feed="https://combuilderses.github.io/events/feed.json"></ote-events> |
| 180 | + </div> |
| 181 | + </section> |
| 182 | + |
| 183 | + <section class="panel" aria-labelledby="snippet-heading"> |
| 184 | + <h2 id="snippet-heading">Copy-paste snippet</h2> |
| 185 | + <p class="hint">This is the exact markup for the configuration above.</p> |
| 186 | + <p class="hint"> |
| 187 | + The snippet uses a fixed widget version. Use |
| 188 | + <code>/embed/latest/</code> only when you explicitly want automatic |
| 189 | + updates. |
| 190 | + </p> |
| 191 | + <p class="hint error" id="data-error" hidden></p> |
| 192 | + <div class="snippet-box"> |
| 193 | + <pre><code id="snippet-code" class="language-html"></code></pre> |
| 194 | + <button type="button" id="copy-button">Copy</button> |
| 195 | + </div> |
| 196 | + </section> |
| 197 | + |
| 198 | + <section class="panel versioning-guide" aria-labelledby="versioning-heading"> |
| 199 | + <h2 id="versioning-heading">Versioning</h2> |
| 200 | + <p> |
| 201 | + Production embeds should use a fixed version URL so future widget |
| 202 | + changes do not alter existing sites without an explicit upgrade. |
| 203 | + </p> |
| 204 | + <dl class="version-url-list"> |
| 205 | + <div> |
| 206 | + <dt>Recommended</dt> |
| 207 | + <dd><code>https://tools.opentechevents.org/embed/v0.1.1/ote-events.js</code></dd> |
| 208 | + </div> |
| 209 | + <div> |
| 210 | + <dt>Automatic updates</dt> |
| 211 | + <dd><code>https://tools.opentechevents.org/embed/latest/ote-events.js</code></dd> |
| 212 | + </div> |
| 213 | + <div> |
| 214 | + <dt>Legacy alias</dt> |
| 215 | + <dd><code>https://tools.opentechevents.org/embed/ote-events.js</code></dd> |
| 216 | + </div> |
| 217 | + </dl> |
| 218 | + <p> |
| 219 | + The widget follows semantic versioning: patch releases are compatible |
| 220 | + fixes, minor releases add compatible features, and major releases may |
| 221 | + require migration. Check the changelog before changing the version used |
| 222 | + by a production page. |
| 223 | + </p> |
| 224 | + <div class="resource-links"> |
| 225 | + <a href="https://github.com/OpenTechEvents/ote-tools/blob/main/apps/embed/CHANGELOG.md" target="_blank" rel="noopener"> |
| 226 | + View the changelog |
| 227 | + </a> |
| 228 | + <a href="https://github.com/OpenTechEvents/ote-tools/releases?q=embed-v&expanded=true" target="_blank" rel="noopener"> |
| 229 | + View embed releases |
| 230 | + </a> |
| 231 | + </div> |
| 232 | + </section> |
| 233 | + |
| 234 | + <section class="panel agent-resource" aria-labelledby="agent-resource-heading"> |
| 235 | + <h2 id="agent-resource-heading">Using AI agents?</h2> |
| 236 | + <p> |
| 237 | + The embed package includes an agent-facing guide with the typed |
| 238 | + <code>eventActions</code> contract, placement rules, and the tests that |
| 239 | + act as living documentation. |
| 240 | + </p> |
| 241 | + <div class="resource-links"> |
| 242 | + <a href="https://github.com/OpenTechEvents/ote-tools/blob/main/apps/embed/CLAUDE.md" target="_blank" rel="noopener"> |
| 243 | + Read the agent guide |
| 244 | + </a> |
| 245 | + <a href="https://github.com/OpenTechEvents/ote-tools/blob/main/apps/embed/CHANGELOG.md" target="_blank" rel="noopener"> |
| 246 | + View the changelog |
| 247 | + </a> |
| 248 | + </div> |
| 249 | + </section> |
| 250 | + </div> |
| 251 | + </main> |
| 252 | + |
| 253 | + <script type="module" src="./ote-events.js"></script> |
| 254 | + <script defer src="https://cdn.jsdelivr.net/npm/@highlightjs/cdn-assets@11.11.1/highlight.min.js"></script> |
| 255 | + <script type="module" src="./playground.js"></script> |
| 256 | +</body> |
| 257 | +</html> |
0 commit comments