@unson/brainbase-mcp 0.41.2 → 0.41.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/contracts/judgment-dag/digest.json +2 -2
- package/dist/judgment-history-http.js +52 -11
- package/dist/judgment-history.d.ts +70 -2
- package/dist/judgment-history.js +381 -122
- package/dist/local-web-host.js +1 -1
- package/package.json +5 -3
- package/ui/brainbase-tokens.css +17 -0
- package/ui/foundation-overview.css +18 -0
- package/ui/foundation-overview.js +77 -77
- package/ui/graph-own-share.js +30 -3
- package/ui/judgment-history.css +215 -22
- package/ui/judgment-history.js +398 -104
- package/ui/local-web-shell.css +1 -0
- package/ui/local-web-shell.js +3 -0
- package/ui/native-scrollbars.css +18 -0
- package/ui/native-scrollbars.js +18 -0
- package/ui/workspace-kit.css +36 -0
- package/ui/workspace-kit.js +65 -0
package/ui/local-web-shell.css
CHANGED
package/ui/local-web-shell.js
CHANGED
|
@@ -26,6 +26,7 @@ import { createMeetingMinutesStorageExtension } from './meeting-minutes-storage.
|
|
|
26
26
|
import { createMeetingMinutesLineageExtension } from './meeting-minutes-lineage-http.js';
|
|
27
27
|
import { createWorldModelView } from './world-model-view.js';
|
|
28
28
|
import { createGraphClient } from './graph-view-shared.js';
|
|
29
|
+
import { installNativeScrollbars } from './native-scrollbars.js';
|
|
29
30
|
|
|
30
31
|
export const LOCAL_WEB_SHELL_CONTRACT_VERSION = 'brainbase.local-web-shell.v1';
|
|
31
32
|
|
|
@@ -459,6 +460,7 @@ export function createLocalWebShell({
|
|
|
459
460
|
}
|
|
460
461
|
shell.append(sidebar, backdrop, workspace, railAside);
|
|
461
462
|
root.replaceChildren(shell);
|
|
463
|
+
const stopScrollbars = doc.documentElement?.classList && doc.addEventListener ? installNativeScrollbars(doc) : () => {};
|
|
462
464
|
|
|
463
465
|
// The rail column shows only while the active screen is mounted and has one.
|
|
464
466
|
function updateRail() {
|
|
@@ -493,6 +495,7 @@ export function createLocalWebShell({
|
|
|
493
495
|
}
|
|
494
496
|
|
|
495
497
|
const controller = {
|
|
498
|
+
destroy() { stopScrollbars(); for (const view of mounted.values()) view?.destroy?.(); root.replaceChildren(); },
|
|
496
499
|
get state() {
|
|
497
500
|
return { active, status, mounted: [...mounted.keys()] };
|
|
498
501
|
},
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
@property --bb-scrollbar-opacity { syntax: "<number>"; inherits: false; initial-value: 0; }
|
|
3
|
+
:root.bb-native-scrollbars, .bb-native-scrollbars :is(.bb-scrollable, .sidebar, .bb-shell-sidebar, .bb-shell-main, .bb-shell-rail, .bb-ws-dialog, .mutation-dialog) {
|
|
4
|
+
--bb-scrollbar-rgb: var(--bb-color-scrollbar-rgb); --bb-scrollbar-opacity: 0;
|
|
5
|
+
scrollbar-width: thin;
|
|
6
|
+
scrollbar-color: rgba(var(--bb-scrollbar-rgb),var(--bb-scrollbar-opacity)) transparent;
|
|
7
|
+
transition: --bb-scrollbar-opacity 450ms ease;
|
|
8
|
+
}
|
|
9
|
+
.bb-native-scrollbars :is(.sidebar,.bb-shell-sidebar) { --bb-scrollbar-rgb: var(--bb-color-scrollbar-dark-rgb); }
|
|
10
|
+
:root.bb-native-scrollbars.bb-is-scrolling, .bb-native-scrollbars .bb-is-scrolling { --bb-scrollbar-opacity: .28; }
|
|
11
|
+
:root.bb-native-scrollbars::-webkit-scrollbar, .bb-native-scrollbars :is(.bb-scrollable,.sidebar,.bb-shell-sidebar,.bb-shell-main,.bb-shell-rail,.bb-ws-dialog,.mutation-dialog)::-webkit-scrollbar { width: 6px; height: 6px; }
|
|
12
|
+
:root.bb-native-scrollbars::-webkit-scrollbar-track, .bb-native-scrollbars :is(.bb-scrollable,.sidebar,.bb-shell-sidebar,.bb-shell-main,.bb-shell-rail,.bb-ws-dialog,.mutation-dialog)::-webkit-scrollbar-track { background: transparent; }
|
|
13
|
+
:root.bb-native-scrollbars::-webkit-scrollbar-thumb, .bb-native-scrollbars :is(.bb-scrollable,.sidebar,.bb-shell-sidebar,.bb-shell-main,.bb-shell-rail,.bb-ws-dialog,.mutation-dialog)::-webkit-scrollbar-thumb { background: rgba(var(--bb-scrollbar-rgb),var(--bb-scrollbar-opacity)); border-radius: 8px; }
|
|
14
|
+
@media (prefers-reduced-motion: reduce) { :root.bb-native-scrollbars, .bb-native-scrollbars :is(.bb-scrollable,.sidebar,.bb-shell-sidebar,.bb-shell-main,.bb-shell-rail,.bb-ws-dialog,.mutation-dialog) { transition: none; } }
|
|
15
|
+
@media (forced-colors: active) {
|
|
16
|
+
:root.bb-native-scrollbars, .bb-native-scrollbars :is(.bb-scrollable,.sidebar,.bb-shell-sidebar,.bb-shell-main,.bb-shell-rail,.bb-ws-dialog,.mutation-dialog) { scrollbar-width: auto; scrollbar-color: auto; }
|
|
17
|
+
:root.bb-native-scrollbars::-webkit-scrollbar-thumb, .bb-native-scrollbars :is(.bb-scrollable,.sidebar,.bb-shell-sidebar,.bb-shell-main,.bb-shell-rail,.bb-ws-dialog,.mutation-dialog)::-webkit-scrollbar-thumb { background: CanvasText; }
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Animate native scrollbars without replacing scrolling or input handling. */
|
|
2
|
+
export function installNativeScrollbars(doc = document) {
|
|
3
|
+
const timers = new Map();
|
|
4
|
+
doc.documentElement.classList.add('bb-native-scrollbars');
|
|
5
|
+
const activate = event => {
|
|
6
|
+
const target = event.target === doc ? doc.scrollingElement : event.target;
|
|
7
|
+
if (!target?.classList) return;
|
|
8
|
+
target.classList.add('bb-scrollable', 'bb-is-scrolling');
|
|
9
|
+
clearTimeout(timers.get(target));
|
|
10
|
+
timers.set(target, setTimeout(() => { target.classList.remove('bb-is-scrolling'); timers.delete(target); }, 800));
|
|
11
|
+
};
|
|
12
|
+
doc.addEventListener('scroll', activate, true);
|
|
13
|
+
return () => {
|
|
14
|
+
doc.removeEventListener('scroll', activate, true);
|
|
15
|
+
for (const [target, timer] of timers) { clearTimeout(timer); target.classList.remove('bb-is-scrolling'); }
|
|
16
|
+
timers.clear(); doc.documentElement.classList.remove('bb-native-scrollbars');
|
|
17
|
+
};
|
|
18
|
+
}
|
package/ui/workspace-kit.css
CHANGED
|
@@ -494,3 +494,39 @@
|
|
|
494
494
|
}
|
|
495
495
|
|
|
496
496
|
}
|
|
497
|
+
|
|
498
|
+
/* Shared help, modal, disclosures and persistent notifications. */
|
|
499
|
+
.bb-ws-help { position: relative; display: inline-flex; vertical-align: middle; }
|
|
500
|
+
.bb-ws-help-button { display: grid; place-items: center; width: 16px; height: 16px; padding: 0; border: 1px solid var(--bb-color-muted); border-radius: 50%; background: transparent; color: var(--bb-color-muted); font: italic 11px var(--bb-font-help); cursor: help; }
|
|
501
|
+
.bb-ws-help-bubble { position: absolute; z-index: 70; bottom: calc(100% + 8px); left: 50%; width: min(300px,70vw); padding: 10px 12px; border: 1px solid var(--bb-color-border); border-radius: 8px; background: var(--bb-color-panel); color: var(--bb-color-ink); font-size: 12px; font-weight: normal; line-height: 1.7; box-shadow: var(--bb-shadow-help); opacity: 0; visibility: hidden; transform: translate(-50%,4px); transition: opacity 160ms ease,transform 160ms ease,visibility 160ms; pointer-events: none; }
|
|
502
|
+
.bb-ws-help-bubble::after { content: ''; position: absolute; top: 100%; left: 0; width: 100%; height: 10px; }
|
|
503
|
+
.bb-ws-help:not(.is-dismissed):is(:hover,:focus-within,.is-open) .bb-ws-help-bubble { opacity: 1; visibility: visible; transform: translate(-50%,0); pointer-events: auto; }
|
|
504
|
+
.bb-ws-dialog { width: min(720px,calc(100vw - 36px)); max-height: calc(100dvh - 48px); box-sizing: border-box; padding: 0; overflow: auto; border: 1px solid var(--bb-color-border); border-radius: 12px; background: var(--bb-color-panel); color: var(--bb-color-ink); font: inherit; }
|
|
505
|
+
.bb-ws-dialog::backdrop { background: var(--bb-color-dialog-overlay); }
|
|
506
|
+
.bb-ws-dialog-head { display: flex; justify-content: space-between; align-items: start; gap: 20px; padding: 24px 28px; border-bottom: 1px solid var(--bb-color-border); }
|
|
507
|
+
.bb-ws-dialog-head h2 { margin: 0; font-size: 22px; line-height: 1.5; }
|
|
508
|
+
.bb-ws-dialog-body { padding: 28px; }
|
|
509
|
+
.bb-ws-disclosure { border-top: 1px solid var(--bb-color-border); }
|
|
510
|
+
.bb-ws-disclosure > summary { display: flex; align-items: center; gap: 12px; padding: 16px 0; cursor: pointer; list-style: none; }
|
|
511
|
+
.bb-ws-disclosure > summary::-webkit-details-marker { display: none; }
|
|
512
|
+
.bb-ws-disclosure > summary::before { content: '›'; font-size: 20px; color: var(--bb-color-muted); }
|
|
513
|
+
.bb-ws-disclosure[open] > summary::before { transform: rotate(90deg); }
|
|
514
|
+
.bb-ws-disclosure > summary h2 { margin: 0; font-size: 22px; line-height: 1.4; }
|
|
515
|
+
.bb-ws-disclosure > :not(summary) { margin: 0 0 18px 25px; }
|
|
516
|
+
.bb-ws-disclosure > summary:focus-visible, .bb-ws-help-button:focus-visible { outline: 2px solid var(--bb-color-focus); outline-offset: 3px; }
|
|
517
|
+
.bb-ws-error-stack { position: absolute; z-index: 55; top: 0; right: 0; width: min(300px,100%); max-height: none; padding-bottom: 64px; pointer-events: none; box-sizing: border-box; overflow: visible; }
|
|
518
|
+
.bb-ws-error-list { display: grid; gap: 6px; }
|
|
519
|
+
.bb-ws-error-count { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
|
|
520
|
+
.bb-ws-error-card { display: flex; align-items: start; gap: 8px; box-sizing: border-box; width: 100%; padding: 8px 10px; border: 1px solid var(--bb-color-notice-border); border-left: 3px solid var(--bb-color-notice-danger); border-radius: 4px; background: var(--bb-color-notice-background); backdrop-filter: blur(5px); color: var(--bb-color-notice-text); font-size: 12px; line-height: 1.5; pointer-events: auto; }
|
|
521
|
+
.bb-ws-error-card.is-warning { border-left-color: var(--bb-color-notice-warning); }
|
|
522
|
+
.bb-ws-error-card > details { flex: 1; min-width: 0; }
|
|
523
|
+
.bb-ws-error-card summary { display: flex; align-items: center; gap: 6px; list-style: none; cursor: pointer; }
|
|
524
|
+
.bb-ws-error-card summary::-webkit-details-marker { display: none; }
|
|
525
|
+
.bb-ws-error-card summary > span:last-child { overflow-wrap: anywhere; }
|
|
526
|
+
.bb-ws-error-symbol { display: grid; flex: none; place-items: center; width: 14px; height: 14px; border: 1px solid var(--bb-color-notice-danger-symbol-border); color: var(--bb-color-notice-danger-text); border-radius: 3px; }
|
|
527
|
+
.bb-ws-error-card.is-warning .bb-ws-error-symbol { color: var(--bb-color-notice-warning-text); border-color: var(--bb-color-notice-warning-symbol-border); }
|
|
528
|
+
.bb-ws-error-card p { margin: 8px 0 0; overflow-wrap: anywhere; font-size: 11px; }
|
|
529
|
+
.bb-ws-error-card .bb-ws-button { flex: none; min-height: 18px; padding: 0 5px; border: 1px solid var(--bb-color-notice-control-border); border-radius: 4px; background: transparent; color: var(--bb-color-notice-text); font-size: 11px; line-height: 16px; }
|
|
530
|
+
.bb-ws-error-card :is(summary,button):focus-visible { outline: 2px solid var(--bb-color-notice-text); outline-offset: 2px; }
|
|
531
|
+
.bb-ws-inline-error { height: 15px; max-height: 15px; margin: 4px 0; padding: 0; overflow: hidden; color: var(--bb-color-inline-error); font-size: 11px; line-height: 15px; }
|
|
532
|
+
@media (prefers-reduced-motion: reduce) { .bb-ws-help-bubble { transition: none; } }
|
package/ui/workspace-kit.js
CHANGED
|
@@ -230,3 +230,68 @@ export function workspaceSectionTitle(doc, { title, lead } = {}) {
|
|
|
230
230
|
if (lead) wrap.append(el(doc, 'p', { text: lead }));
|
|
231
231
|
return wrap;
|
|
232
232
|
}
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
let workspaceSequence = 0;
|
|
236
|
+
/** Shared explanatory help: hover/focus above the control, click for touch. */
|
|
237
|
+
export function workspaceHelp(doc, { text, label } = {}) {
|
|
238
|
+
const wrap = el(doc, 'span', { className: 'bb-ws-help' });
|
|
239
|
+
const control = workspaceButton(doc, { text: 'i', attrs: { 'aria-label': `${label}の説明`, 'aria-expanded': 'false' } });
|
|
240
|
+
control.className = 'bb-ws-help-button';
|
|
241
|
+
const bubble = el(doc, 'span', { className: 'bb-ws-help-bubble', text, attrs: { id: `bb-ws-help-${++workspaceSequence}`, role: 'tooltip' } });
|
|
242
|
+
control.setAttribute('aria-describedby', bubble.id || bubble.getAttribute?.('id') || bubble.attributes?.id);
|
|
243
|
+
control.addEventListener('click', event => {
|
|
244
|
+
event.stopPropagation(); event.preventDefault();
|
|
245
|
+
const opened = wrap.classList.toggle('is-open');
|
|
246
|
+
wrap.classList.remove('is-dismissed');
|
|
247
|
+
control.setAttribute('aria-expanded', String(opened));
|
|
248
|
+
});
|
|
249
|
+
wrap.addEventListener('mouseleave', () => wrap.classList.remove('is-dismissed'));
|
|
250
|
+
control.addEventListener('blur', () => { wrap.classList.remove('is-open', 'is-dismissed'); control.setAttribute('aria-expanded', 'false'); });
|
|
251
|
+
control.addEventListener('keydown', event => {
|
|
252
|
+
if (event.key !== 'Escape') return;
|
|
253
|
+
wrap.classList.remove('is-open'); wrap.classList.add('is-dismissed');
|
|
254
|
+
control.setAttribute('aria-expanded', 'false'); event.stopPropagation();
|
|
255
|
+
});
|
|
256
|
+
wrap.append(control, bubble); return wrap;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** Native dialog keeps focus trapped, Escape close and focus restoration. */
|
|
260
|
+
export function workspaceDialog(doc, { title, content, opener } = {}) {
|
|
261
|
+
const dialog = el(doc, 'dialog', { className: 'bb-ws-dialog' });
|
|
262
|
+
const headingId = `bb-ws-dialog-${++workspaceSequence}`;
|
|
263
|
+
dialog.setAttribute('aria-labelledby', headingId);
|
|
264
|
+
const head = el(doc, 'header', { className: 'bb-ws-dialog-head' });
|
|
265
|
+
const close = workspaceButton(doc, { text: '×', attrs: { 'aria-label': '閉じる' }, onClick: () => dialog.close() });
|
|
266
|
+
head.append(el(doc, 'h2', { text: title, attrs: { id: headingId } }), close);
|
|
267
|
+
const body = el(doc, 'div', { className: 'bb-ws-dialog-body' }); appendContent(body, doc, content);
|
|
268
|
+
dialog.append(head, body); doc.body.append(dialog);
|
|
269
|
+
dialog.addEventListener('click', event => {
|
|
270
|
+
if (event.target !== dialog) return;
|
|
271
|
+
const rect = dialog.getBoundingClientRect();
|
|
272
|
+
if (event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom) dialog.close();
|
|
273
|
+
});
|
|
274
|
+
dialog.addEventListener('close', () => { dialog.remove(); if (opener?.isConnected) opener.focus(); }, { once: true });
|
|
275
|
+
dialog.showModal(); close.focus(); return dialog;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Persistent, initially closed notification. The caller owns its lifecycle. */
|
|
279
|
+
export function workspaceErrorCard(doc, { title, message, tone = 'danger', onRetry } = {}) {
|
|
280
|
+
const card = el(doc, 'section', { className: `bb-ws-error-card is-${tone}`, attrs: { role: 'listitem' } });
|
|
281
|
+
const details = el(doc, 'details');
|
|
282
|
+
const summary = el(doc, 'summary', { attrs: { 'aria-label': `${title}の通知` } });
|
|
283
|
+
summary.append(el(doc, 'span', { className: 'bb-ws-error-symbol', text: '!', attrs: { 'aria-hidden': 'true' } }), el(doc, 'span', { text: title }));
|
|
284
|
+
details.append(summary, el(doc, 'p', { text: message })); card.append(details);
|
|
285
|
+
if (onRetry) card.append(workspaceButton(doc, { text: '再試行', attrs: { 'aria-label': `${title}を再試行` }, onClick: onRetry }));
|
|
286
|
+
return card;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function workspaceDisclosure(doc, { title, help, content, open = false, onToggle } = {}) {
|
|
290
|
+
const details = el(doc, 'details', { className: 'bb-ws-disclosure' }); details.open = open;
|
|
291
|
+
const summary = el(doc, 'summary');
|
|
292
|
+
summary.append(el(doc, 'h2', { text: title }));
|
|
293
|
+
if (help) summary.append(workspaceHelp(doc, { label: title, text: help }));
|
|
294
|
+
details.append(summary, content);
|
|
295
|
+
if (onToggle) details.addEventListener('toggle', () => onToggle(details.open));
|
|
296
|
+
return details;
|
|
297
|
+
}
|