mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-07-21 12:21:49 +00:00
* feat(career): profile passport wall, home career card, shareable PNG card Career v3, WS2. The identity artifact leaves the plugin tab: - Profile: #v3-profile-passports-mount (core, one div) filled by career on v3:profile-rendered — per-instrument shelves of earned covers, hours, gig count, open-career link. Absent-not-empty. - Home: the plugin-count stat tile becomes #v3-dash-career-slot with the old stat as fallback content; career replaces it with a trading-card tile (leather + foil shine, badge count, hours, closest-stamp ask) on the existing v3:dashboard-rendered event. - Shareable card: static/js/blob-io.js (downloadBlob lifts the idiom duplicated verbatim in settings-io/diagnostics-export — both refactored; copyImageBlob wraps ClipboardItem, returns false to signal the download fallback). Earned passports get Save/Copy card: a natively-drawn 480×640 canvas (leather, stamp ring, stubs+hours line); copy falls back to download with a notice when the clipboard refuses. - Mount-point convention documented in docs/plugin-v3-ui.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(career): external surfaces stay absent until a passport exists CodeRabbit on #955: a bare commitment produced a zero-passport wall and replaced the dashboard fallback. Docs also now say mounts may hold fallback content and plugins REPLACE, never append. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
29 lines
1.1 KiB
JavaScript
29 lines
1.1 KiB
JavaScript
// Blob export helpers — the download idiom that used to be duplicated in
|
|
// settings-io.js and diagnostics-export.js, plus image-to-clipboard for
|
|
// shareable cards/posters. A LEAF module: imports nothing. Classic-script
|
|
// plugins reach it via dynamic import('/static/js/blob-io.js').
|
|
|
|
export function downloadBlob(blob, filename) {
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
// Copy an image blob to the system clipboard. Returns true on success, false
|
|
// when the Clipboard API is unavailable or refuses (insecure context, no user
|
|
// gesture, permission denied) — callers fall back to downloadBlob and say so.
|
|
export async function copyImageBlob(blob) {
|
|
try {
|
|
if (!navigator.clipboard || typeof ClipboardItem === 'undefined') return false;
|
|
await navigator.clipboard.write([new ClipboardItem({ [blob.type || 'image/png']: blob })]);
|
|
return true;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|