Some checks failed
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / build-and-deploy (pull_request) Has been cancelled
CI/CD / test-sqlite (pull_request) Has been cancelled
CI/CD / test-go-pg (pull_request) Has been cancelled
CI/CD / test-frontend (pull_request) Has been cancelled
Prefix enforcement prevents extension CSS from leaking into the kernel
or sibling extensions. All 12 in-tree packages migrated to .ext-{slug}-*
naming convention.
- Add data-ext attribute to extension mount container
- Add CSS linter (scripts/lint-package-css.sh) enforcing .ext-{slug} prefix
- Add kernel CSS contract doc (docs/EXTENSION-CSS.md)
- Migrate 12 packages: chat, dashboard, editor, git-board, hello-dashboard,
icd-test-runner, notes, schedules, sdk-test-runner, tasks,
team-activity-log, workflow-demo (CSS + JS in lockstep)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
85 lines
3.6 KiB
JavaScript
85 lines
3.6 KiB
JavaScript
/**
|
|
* Hello Dashboard — sample extension surface.
|
|
*
|
|
* Platform contract:
|
|
* - Mounts into #extension-mount
|
|
* - window.__MANIFEST__ — surface manifest (json, lowercase keys)
|
|
* - sw.auth.user — authenticated user (from SDK boot)
|
|
* - UI.toast(msg, type) — platform toast (success/error/info/warning)
|
|
* - API._get(path) — authenticated fetch (returns parsed JSON)
|
|
*/
|
|
(function() {
|
|
'use strict';
|
|
|
|
var mount = document.getElementById('extension-mount');
|
|
if (!mount) return;
|
|
|
|
var manifest = window.__MANIFEST__ || {};
|
|
var user = window.sw?.auth?.user || {};
|
|
var isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
|
var name = user.display_name || user.username || 'World';
|
|
|
|
mount.innerHTML =
|
|
'<div class="ext-hello-dashboard">' +
|
|
'<div class="ext-hello-dashboard-header">' +
|
|
'<h1>Hello, ' + esc(name) + '!</h1>' +
|
|
'<p class="ext-hello-dashboard-subtitle">Extension surface <code>' + esc(manifest.id || 'unknown') + '</code> loaded successfully.</p>' +
|
|
'</div>' +
|
|
'<div class="ext-hello-dashboard-cards">' +
|
|
card('Platform Access', (typeof UI !== 'undefined' ? '\u2713 Connected' : '\u2717 Unavailable'),
|
|
'API, Theme, UI primitives available', 'var(--accent)') +
|
|
card('Theme', isDark ? '\uD83C\uDF19 Dark' : '\u2600\uFE0F Light',
|
|
'Reads from platform theme system', '') +
|
|
card('Route', '<code>' + esc(manifest.route || '/s/hello-dashboard') + '</code>',
|
|
'Registered via surface manifest', '') +
|
|
'</div>' +
|
|
'<div class="ext-hello-dashboard-actions">' +
|
|
'<button class="sw-btn sw-btn--primary sw-btn--md" id="helloToast">Show Toast</button>' +
|
|
'<button class="sw-btn sw-btn--secondary sw-btn--md" id="helloApi">Test API</button>' +
|
|
'</div>' +
|
|
'<pre class="ext-hello-dashboard-manifest">' + esc(JSON.stringify(manifest, null, 2)) + '</pre>' +
|
|
'</div>';
|
|
|
|
// Wire toast button
|
|
document.getElementById('helloToast').addEventListener('click', function() {
|
|
if (typeof UI !== 'undefined' && UI.toast) {
|
|
UI.toast('Extension surface is working!', 'success');
|
|
} else {
|
|
alert('Extension surface is working! (UI.toast not available)');
|
|
}
|
|
});
|
|
|
|
// Wire API test button
|
|
document.getElementById('helloApi').addEventListener('click', function() {
|
|
if (typeof API === 'undefined' || !API._get) {
|
|
toast('API module not available', 'error');
|
|
return;
|
|
}
|
|
API._get('/api/v1/surfaces').then(function(resp) {
|
|
toast('API returned ' + (resp.surfaces || []).length + ' registered surfaces', 'info');
|
|
}).catch(function(e) {
|
|
toast('API error: ' + e.message, 'error');
|
|
});
|
|
});
|
|
|
|
function toast(msg, type) {
|
|
if (typeof UI !== 'undefined' && UI.toast) UI.toast(msg, type);
|
|
else alert(msg);
|
|
}
|
|
|
|
function card(title, value, detail, color) {
|
|
var style = color ? ' style="color:' + color + ';"' : '';
|
|
return '<div class="ext-hello-dashboard-card">' +
|
|
'<div class="ext-hello-dashboard-card-title">' + esc(title) + '</div>' +
|
|
'<div class="ext-hello-dashboard-card-value"' + style + '>' + value + '</div>' +
|
|
'<div class="ext-hello-dashboard-card-detail">' + esc(detail) + '</div>' +
|
|
'</div>';
|
|
}
|
|
|
|
function esc(s) {
|
|
var el = document.createElement('span');
|
|
el.textContent = s;
|
|
return el.innerHTML;
|
|
}
|
|
})();
|