|
|
|
|
@ -287,7 +287,7 @@ class FolkTimebankApp extends HTMLElement {
|
|
|
|
|
private poolPointerId: number | null = null;
|
|
|
|
|
private poolPointerStart: { x: number; y: number; cx: number; cy: number } | null = null;
|
|
|
|
|
private poolPanelCollapsed = false;
|
|
|
|
|
private _panelSplitPct = 35;
|
|
|
|
|
private _panelSplitPct = 50;
|
|
|
|
|
private _dividerDragging = false;
|
|
|
|
|
private _dividerDragStartX = 0;
|
|
|
|
|
private _dividerDragStartPct = 0;
|
|
|
|
|
@ -375,12 +375,14 @@ class FolkTimebankApp extends HTMLElement {
|
|
|
|
|
this._history.push(view);
|
|
|
|
|
this.currentView = view;
|
|
|
|
|
const canvasView = this.shadow.getElementById('canvas-view');
|
|
|
|
|
const weaveView = this.shadow.getElementById('weave-view');
|
|
|
|
|
const collabView = this.shadow.getElementById('collaborate-view');
|
|
|
|
|
const dashView = this.shadow.getElementById('dashboard-view');
|
|
|
|
|
if (canvasView) canvasView.style.display = view === 'canvas' ? 'flex' : 'none';
|
|
|
|
|
if (weaveView) weaveView.style.display = 'none';
|
|
|
|
|
if (collabView) collabView.style.display = view === 'collaborate' ? 'flex' : 'none';
|
|
|
|
|
if (dashView) dashView.style.display = view === 'dashboard' ? 'flex' : 'none';
|
|
|
|
|
if (view === 'canvas') { this.resizePoolCanvas(); this.rebuildSidebar(); }
|
|
|
|
|
if (view === 'canvas') { this.resizePoolCanvas(); this.rebuildSidebar(); this.renderCommitmentsList(); }
|
|
|
|
|
if (view === 'collaborate') this.refreshCollaborate();
|
|
|
|
|
if (view === 'dashboard') this.refreshDashboard();
|
|
|
|
|
}
|
|
|
|
|
@ -395,7 +397,7 @@ class FolkTimebankApp extends HTMLElement {
|
|
|
|
|
else this.currentView = 'canvas';
|
|
|
|
|
this.dpr = window.devicePixelRatio || 1;
|
|
|
|
|
this._theme = (localStorage.getItem('rtime-theme') as 'dark' | 'light') || 'dark';
|
|
|
|
|
this._panelSplitPct = parseFloat(localStorage.getItem('rtime-split-pct') || '35');
|
|
|
|
|
this._panelSplitPct = parseFloat(localStorage.getItem('rtime-split-pct') || '50');
|
|
|
|
|
this.render();
|
|
|
|
|
this.applyTheme();
|
|
|
|
|
this.setupPoolPanel();
|
|
|
|
|
@ -524,6 +526,7 @@ class FolkTimebankApp extends HTMLElement {
|
|
|
|
|
|
|
|
|
|
this.buildOrbs();
|
|
|
|
|
this.updateStats();
|
|
|
|
|
this.renderCommitmentsList();
|
|
|
|
|
this.rebuildSidebar();
|
|
|
|
|
this.applyRestoredConnections();
|
|
|
|
|
|
|
|
|
|
@ -544,13 +547,52 @@ class FolkTimebankApp extends HTMLElement {
|
|
|
|
|
<style>${CSS_TEXT}</style>
|
|
|
|
|
<div class="main">
|
|
|
|
|
<div id="canvas-view">
|
|
|
|
|
<!-- Left pool panel -->
|
|
|
|
|
<!-- Left: commitment entry form -->
|
|
|
|
|
<div class="form-panel" id="formPanel">
|
|
|
|
|
<div class="form-panel-header">
|
|
|
|
|
<span>Pledge Time</span>
|
|
|
|
|
<button class="theme-toggle" id="themeToggle" title="Toggle light/dark theme">\u2600</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="inline-form" id="inlineForm">
|
|
|
|
|
<div class="inline-form-field">
|
|
|
|
|
<label>Your Name</label>
|
|
|
|
|
<input type="text" id="inlineName" placeholder="e.g. Dana Lee">
|
|
|
|
|
</div>
|
|
|
|
|
<div class="inline-form-field">
|
|
|
|
|
<label>Skill Category</label>
|
|
|
|
|
<select id="inlineSkill">
|
|
|
|
|
<option value="facilitation">Facilitation</option>
|
|
|
|
|
<option value="design">Design</option>
|
|
|
|
|
<option value="tech">Tech</option>
|
|
|
|
|
<option value="outreach">Outreach</option>
|
|
|
|
|
<option value="logistics">Logistics</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="inline-form-row">
|
|
|
|
|
<div class="inline-form-field" style="flex:1">
|
|
|
|
|
<label>Hours</label>
|
|
|
|
|
<input type="number" id="inlineHours" min="1" max="10" value="2">
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="inline-form-field">
|
|
|
|
|
<label>Description</label>
|
|
|
|
|
<input type="text" id="inlineDesc" placeholder="What will you contribute?">
|
|
|
|
|
</div>
|
|
|
|
|
<button class="pledge-btn" id="pledgeBtn">Pledge to Pool</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="commitments-list-header">
|
|
|
|
|
<span>Commitments</span>
|
|
|
|
|
<span class="commitments-count" id="commitmentsCount">0</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="commitments-list" id="commitmentsList"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- Resizable divider -->
|
|
|
|
|
<div class="panel-divider" id="panelDivider"><div class="divider-pip"></div></div>
|
|
|
|
|
<!-- Right: pool visualization -->
|
|
|
|
|
<div class="pool-panel" id="poolPanel">
|
|
|
|
|
<div class="pool-panel-header">
|
|
|
|
|
<span>Commitment Pool</span>
|
|
|
|
|
<span class="pool-hint">drag orb to weave \u2192</span>
|
|
|
|
|
<button class="theme-toggle" id="themeToggle" title="Toggle light/dark theme">☀</button>
|
|
|
|
|
<button id="poolPanelToggle" title="Collapse panel">\u27E8</button>
|
|
|
|
|
<button id="poolPanelToggle" title="Toggle weaving view" class="weave-toggle-btn">\u2694 Weave</button>
|
|
|
|
|
</div>
|
|
|
|
|
<canvas id="pool-canvas"></canvas>
|
|
|
|
|
<div class="pool-legend" id="poolLegend">
|
|
|
|
|
@ -570,22 +612,17 @@ class FolkTimebankApp extends HTMLElement {
|
|
|
|
|
<div class="pool-detail-hours" id="detailHours"></div>
|
|
|
|
|
<div class="pool-detail-desc" id="detailDesc"></div>
|
|
|
|
|
<div class="pool-detail-woven" id="detailWoven"></div>
|
|
|
|
|
<button class="pool-detail-drag-btn" id="detailDragBtn">Drag to Weave \u2192</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="pool-panel-sidebar" id="poolSidebar">
|
|
|
|
|
<div class="sidebar-section">Woven Tasks</div>
|
|
|
|
|
<div id="sidebarTasks"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="add-btn" id="addBtn">+ Pledge Time</button>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- Resizable divider -->
|
|
|
|
|
<div class="panel-divider" id="panelDivider"><div class="divider-pip"></div></div>
|
|
|
|
|
<!-- SVG infinite canvas -->
|
|
|
|
|
</div>
|
|
|
|
|
<!-- Weaving view (hidden by default, toggled via button) -->
|
|
|
|
|
<div id="weave-view" style="display:none">
|
|
|
|
|
<div class="weave-view-header">
|
|
|
|
|
<button class="weave-back-btn" id="weaveBackBtn">\u2190 Back to Pool</button>
|
|
|
|
|
<span>Commitment Weaving</span>
|
|
|
|
|
<span class="canvas-wrap-hint">connect commitments to projects</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="canvas-wrap" id="canvasWrap">
|
|
|
|
|
<div class="canvas-wrap-header">
|
|
|
|
|
<span>Commitment Weaving</span>
|
|
|
|
|
<span class="canvas-wrap-hint">connect commitments to projects</span>
|
|
|
|
|
</div>
|
|
|
|
|
<svg id="weave-svg" xmlns="http://www.w3.org/2000/svg">
|
|
|
|
|
<defs>
|
|
|
|
|
<pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse">
|
|
|
|
|
@ -799,31 +836,19 @@ class FolkTimebankApp extends HTMLElement {
|
|
|
|
|
this.applyTheme();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Pool panel toggle
|
|
|
|
|
// Weave toggle — switches to weaving SVG view
|
|
|
|
|
this.shadow.getElementById('poolPanelToggle')!.addEventListener('click', () => {
|
|
|
|
|
this.poolPanelCollapsed = !this.poolPanelCollapsed;
|
|
|
|
|
const panel = this.shadow.getElementById('poolPanel')!;
|
|
|
|
|
panel.classList.toggle('collapsed', this.poolPanelCollapsed);
|
|
|
|
|
const divider = this.shadow.getElementById('panelDivider');
|
|
|
|
|
if (divider) divider.style.display = this.poolPanelCollapsed ? 'none' : '';
|
|
|
|
|
const btn = this.shadow.getElementById('poolPanelToggle')!;
|
|
|
|
|
btn.textContent = this.poolPanelCollapsed ? '\u27E9' : '\u27E8';
|
|
|
|
|
btn.title = this.poolPanelCollapsed ? 'Expand panel' : 'Collapse panel';
|
|
|
|
|
if (!this.poolPanelCollapsed) setTimeout(() => { this.applyPanelSplit(); }, 50);
|
|
|
|
|
this.shadow.getElementById('canvas-view')!.style.display = 'none';
|
|
|
|
|
this.shadow.getElementById('weave-view')!.style.display = 'flex';
|
|
|
|
|
});
|
|
|
|
|
this.shadow.getElementById('weaveBackBtn')!.addEventListener('click', () => {
|
|
|
|
|
this.shadow.getElementById('weave-view')!.style.display = 'none';
|
|
|
|
|
this.shadow.getElementById('canvas-view')!.style.display = 'flex';
|
|
|
|
|
this.resizePoolCanvas();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Add commitment modal
|
|
|
|
|
const modal = this.shadow.getElementById('modalOverlay')!;
|
|
|
|
|
this.shadow.getElementById('addBtn')!.addEventListener('click', () => {
|
|
|
|
|
modal.classList.add('visible');
|
|
|
|
|
(this.shadow.getElementById('modalName') as HTMLInputElement).value = '';
|
|
|
|
|
(this.shadow.getElementById('modalHours') as HTMLInputElement).value = '2';
|
|
|
|
|
(this.shadow.getElementById('modalDesc') as HTMLInputElement).value = '';
|
|
|
|
|
(this.shadow.getElementById('modalName') as HTMLInputElement).focus();
|
|
|
|
|
});
|
|
|
|
|
this.shadow.getElementById('modalCancel')!.addEventListener('click', () => modal.classList.remove('visible'));
|
|
|
|
|
modal.addEventListener('click', (e) => { if (e.target === modal) modal.classList.remove('visible'); });
|
|
|
|
|
this.shadow.getElementById('modalSubmit')!.addEventListener('click', () => this.submitCommitment());
|
|
|
|
|
// Inline commitment form
|
|
|
|
|
this.shadow.getElementById('pledgeBtn')!.addEventListener('click', () => this.submitCommitment());
|
|
|
|
|
|
|
|
|
|
// Pool pointer events — including long-press drag-to-canvas
|
|
|
|
|
this.canvas.addEventListener('pointerdown', (e) => this.onPoolPointerDown(e));
|
|
|
|
|
@ -944,10 +969,9 @@ class FolkTimebankApp extends HTMLElement {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private applyPanelSplit() {
|
|
|
|
|
const panel = this.shadow.getElementById('poolPanel');
|
|
|
|
|
const panel = this.shadow.getElementById('formPanel');
|
|
|
|
|
const divider = this.shadow.getElementById('panelDivider');
|
|
|
|
|
if (!panel) return;
|
|
|
|
|
if (this.poolPanelCollapsed) return;
|
|
|
|
|
panel.style.width = this._panelSplitPct + '%';
|
|
|
|
|
if (divider) divider.style.display = '';
|
|
|
|
|
this.resizePoolCanvas();
|
|
|
|
|
@ -1175,11 +1199,11 @@ class FolkTimebankApp extends HTMLElement {
|
|
|
|
|
// ── Submit commitment ──
|
|
|
|
|
|
|
|
|
|
private async submitCommitment() {
|
|
|
|
|
const name = (this.shadow.getElementById('modalName') as HTMLInputElement).value.trim();
|
|
|
|
|
const skill = (this.shadow.getElementById('modalSkill') as HTMLSelectElement).value;
|
|
|
|
|
const hours = Math.max(1, Math.min(10, parseInt((this.shadow.getElementById('modalHours') as HTMLInputElement).value) || 2));
|
|
|
|
|
const desc = (this.shadow.getElementById('modalDesc') as HTMLInputElement).value.trim() || (SKILL_LABELS[skill] || skill) + ' contribution';
|
|
|
|
|
if (!name) { (this.shadow.getElementById('modalName') as HTMLInputElement).focus(); return; }
|
|
|
|
|
const name = (this.shadow.getElementById('inlineName') as HTMLInputElement).value.trim();
|
|
|
|
|
const skill = (this.shadow.getElementById('inlineSkill') as HTMLSelectElement).value;
|
|
|
|
|
const hours = Math.max(1, Math.min(10, parseInt((this.shadow.getElementById('inlineHours') as HTMLInputElement).value) || 2));
|
|
|
|
|
const desc = (this.shadow.getElementById('inlineDesc') as HTMLInputElement).value.trim() || (SKILL_LABELS[skill] || skill) + ' contribution';
|
|
|
|
|
if (!name) { (this.shadow.getElementById('inlineName') as HTMLInputElement).focus(); return; }
|
|
|
|
|
|
|
|
|
|
const c: Commitment = { id: 'local-' + Date.now(), memberName: name, skill, hours, desc };
|
|
|
|
|
|
|
|
|
|
@ -1206,7 +1230,33 @@ class FolkTimebankApp extends HTMLElement {
|
|
|
|
|
this.ripples.push(new Ripple(this.basketCX - 15, this.basketCY + 10, SKILL_COLORS[skill] || '#8b5cf6'));
|
|
|
|
|
}, 400);
|
|
|
|
|
this.updateStats();
|
|
|
|
|
this.shadow.getElementById('modalOverlay')!.classList.remove('visible');
|
|
|
|
|
this.renderCommitmentsList();
|
|
|
|
|
|
|
|
|
|
// Clear form fields
|
|
|
|
|
(this.shadow.getElementById('inlineDesc') as HTMLInputElement).value = '';
|
|
|
|
|
(this.shadow.getElementById('inlineHours') as HTMLInputElement).value = '2';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private renderCommitmentsList() {
|
|
|
|
|
const list = this.shadow.getElementById('commitmentsList');
|
|
|
|
|
const countEl = this.shadow.getElementById('commitmentsCount');
|
|
|
|
|
if (!list) return;
|
|
|
|
|
if (countEl) countEl.textContent = String(this.commitments.length);
|
|
|
|
|
list.innerHTML = '';
|
|
|
|
|
for (const c of [...this.commitments].reverse()) {
|
|
|
|
|
const color = SKILL_COLORS[c.skill] || '#8b5cf6';
|
|
|
|
|
const avail = this.availableHours(c.id);
|
|
|
|
|
const wovenLabel = avail < c.hours ? ` <span class="cl-woven">${c.hours - avail}h woven</span>` : '';
|
|
|
|
|
const item = document.createElement('div');
|
|
|
|
|
item.className = 'cl-item';
|
|
|
|
|
item.innerHTML = `<div class="cl-dot" style="background:${color}"></div>
|
|
|
|
|
<div class="cl-info">
|
|
|
|
|
<div class="cl-name">${c.memberName}</div>
|
|
|
|
|
<div class="cl-meta">${SKILL_LABELS[c.skill] || c.skill} \u00b7 ${c.hours}h${wovenLabel}</div>
|
|
|
|
|
<div class="cl-desc">${c.desc}</div>
|
|
|
|
|
</div>`;
|
|
|
|
|
list.appendChild(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Stats bar ──
|
|
|
|
|
@ -3028,9 +3078,9 @@ class FolkTimebankApp extends HTMLElement {
|
|
|
|
|
if (this._tour) return;
|
|
|
|
|
const { TourEngine } = await import('../../../shared/tour-engine');
|
|
|
|
|
this._tour = new TourEngine(this.shadow as unknown as ShadowRoot, [
|
|
|
|
|
{ target: '.pool-panel-header', title: 'Canvas & Collaborate', message: 'The Canvas shows commitment orbs alongside the weaving SVG. Collaborate matches intents via the solver.' },
|
|
|
|
|
{ target: '#pool-canvas', title: 'Commitment Pool', message: 'Each floating orb represents a time commitment — sized by hours, colored by skill. Long-press to drag onto the canvas.' },
|
|
|
|
|
{ target: '#addBtn', title: 'Add a Commitment', message: 'Pledge your hours with a skill category. Your commitment joins the pool for others to see.', advanceOnClick: true },
|
|
|
|
|
{ target: '.form-panel-header', title: 'Pledge Time', message: 'Use the form to pledge your hours with a skill category. Commitments appear in the pool.' },
|
|
|
|
|
{ target: '#inlineForm', title: 'Commitment Form', message: 'Fill in your name, skill, hours, and description, then click Pledge to Pool.' },
|
|
|
|
|
{ target: '#pool-canvas', title: 'Commitment Pool', message: 'Each floating orb represents a time commitment — sized by hours, colored by skill.' },
|
|
|
|
|
{ target: '.pool-legend', title: 'Community Stats', message: 'See total hours available and how many contributors are in the pool at a glance.' },
|
|
|
|
|
], 'rtime_tour_done', () => this.shadow.querySelector('.main') as HTMLElement);
|
|
|
|
|
}
|
|
|
|
|
@ -3590,7 +3640,7 @@ const CSS_TEXT = `
|
|
|
|
|
|
|
|
|
|
.main { flex: 1; position: relative; overflow: hidden; }
|
|
|
|
|
|
|
|
|
|
/* Unified canvas view: pool panel + SVG canvas side by side */
|
|
|
|
|
/* Unified canvas view: form panel + pool visualization side by side */
|
|
|
|
|
#canvas-view {
|
|
|
|
|
display: flex;
|
|
|
|
|
width: 100%; height: 100%;
|
|
|
|
|
@ -3598,9 +3648,34 @@ const CSS_TEXT = `
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pool panel (left side) */
|
|
|
|
|
.pool-panel {
|
|
|
|
|
min-width: 180px;
|
|
|
|
|
/* Weave view (full screen SVG canvas, toggled from pool) */
|
|
|
|
|
#weave-view {
|
|
|
|
|
display: none;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
width: 100%; height: 100%;
|
|
|
|
|
position: absolute; top: 0; left: 0;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
.weave-view-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 1rem;
|
|
|
|
|
padding: 0.5rem 0.75rem;
|
|
|
|
|
font-size: 0.82rem; font-weight: 600; color: #94a3b8;
|
|
|
|
|
text-transform: uppercase; letter-spacing: 0.04em;
|
|
|
|
|
border-bottom: 1px solid #334155; flex-shrink: 0;
|
|
|
|
|
background: #1e293b;
|
|
|
|
|
}
|
|
|
|
|
.weave-back-btn {
|
|
|
|
|
background: none; border: 1px solid #475569; border-radius: 0.375rem;
|
|
|
|
|
color: #94a3b8; font-size: 0.82rem; cursor: pointer; padding: 0.3rem 0.75rem;
|
|
|
|
|
transition: all 0.15s; text-transform: none; letter-spacing: normal;
|
|
|
|
|
}
|
|
|
|
|
.weave-back-btn:hover { border-color: #8b5cf6; color: #e2e8f0; }
|
|
|
|
|
|
|
|
|
|
/* Form panel (left side) — commitment entry */
|
|
|
|
|
.form-panel {
|
|
|
|
|
min-width: 240px;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
background: #1e293b;
|
|
|
|
|
border-right: 1px solid #334155;
|
|
|
|
|
@ -3610,12 +3685,7 @@ const CSS_TEXT = `
|
|
|
|
|
position: relative;
|
|
|
|
|
transition: width 0.2s ease;
|
|
|
|
|
}
|
|
|
|
|
.pool-panel.collapsed { width: 40px; }
|
|
|
|
|
.pool-panel.collapsed #pool-canvas,
|
|
|
|
|
.pool-panel.collapsed .pool-detail,
|
|
|
|
|
.pool-panel.collapsed .pool-panel-sidebar,
|
|
|
|
|
.pool-panel.collapsed .add-btn { display: none; }
|
|
|
|
|
.pool-panel-header {
|
|
|
|
|
.form-panel-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
@ -3628,12 +3698,147 @@ const CSS_TEXT = `
|
|
|
|
|
border-bottom: 1px solid #334155;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
.pool-panel-header button {
|
|
|
|
|
.form-panel-header button {
|
|
|
|
|
background: none; border: 1px solid #475569; border-radius: 0.25rem;
|
|
|
|
|
color: #94a3b8; font-size: 0.85rem; cursor: pointer; padding: 0.1rem 0.4rem;
|
|
|
|
|
line-height: 1; transition: border-color 0.15s;
|
|
|
|
|
}
|
|
|
|
|
.pool-panel-header button:hover { border-color: #8b5cf6; color: #e2e8f0; }
|
|
|
|
|
.form-panel-header button:hover { border-color: #8b5cf6; color: #e2e8f0; }
|
|
|
|
|
|
|
|
|
|
/* Inline commitment form */
|
|
|
|
|
.inline-form {
|
|
|
|
|
padding: 0.75rem;
|
|
|
|
|
border-bottom: 1px solid #334155;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
.inline-form-field {
|
|
|
|
|
margin-bottom: 0.5rem;
|
|
|
|
|
}
|
|
|
|
|
.inline-form-field label {
|
|
|
|
|
display: block;
|
|
|
|
|
font-size: 0.72rem;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #94a3b8;
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
letter-spacing: 0.03em;
|
|
|
|
|
margin-bottom: 0.2rem;
|
|
|
|
|
}
|
|
|
|
|
.inline-form-field input,
|
|
|
|
|
.inline-form-field select {
|
|
|
|
|
width: 100%;
|
|
|
|
|
padding: 0.4rem 0.55rem;
|
|
|
|
|
background: #0f172a;
|
|
|
|
|
border: 1px solid #334155;
|
|
|
|
|
border-radius: 0.375rem;
|
|
|
|
|
color: #e2e8f0;
|
|
|
|
|
font-size: 0.82rem;
|
|
|
|
|
transition: border-color 0.15s;
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
}
|
|
|
|
|
.inline-form-field input:focus,
|
|
|
|
|
.inline-form-field select:focus {
|
|
|
|
|
outline: none;
|
|
|
|
|
border-color: #8b5cf6;
|
|
|
|
|
}
|
|
|
|
|
.inline-form-row {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 0.5rem;
|
|
|
|
|
}
|
|
|
|
|
.pledge-btn {
|
|
|
|
|
width: 100%;
|
|
|
|
|
padding: 0.5rem 0.75rem;
|
|
|
|
|
margin-top: 0.25rem;
|
|
|
|
|
background: linear-gradient(135deg, #8b5cf6, #ec4899);
|
|
|
|
|
color: #fff;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 0.5rem;
|
|
|
|
|
font-size: 0.82rem;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
box-shadow: 0 4px 16px rgba(139,92,246,0.3);
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
}
|
|
|
|
|
.pledge-btn:hover { transform: translateY(-1px); box-shadow: 0 6px 20px rgba(139,92,246,0.4); }
|
|
|
|
|
|
|
|
|
|
/* Commitments list */
|
|
|
|
|
.commitments-list-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
padding: 0.5rem 0.75rem;
|
|
|
|
|
font-size: 0.72rem;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #64748b;
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
letter-spacing: 0.04em;
|
|
|
|
|
border-bottom: 1px solid #334155;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
.commitments-count {
|
|
|
|
|
background: #334155;
|
|
|
|
|
color: #94a3b8;
|
|
|
|
|
font-size: 0.68rem;
|
|
|
|
|
padding: 0.1rem 0.4rem;
|
|
|
|
|
border-radius: 0.25rem;
|
|
|
|
|
min-width: 1.2rem;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
.commitments-list {
|
|
|
|
|
flex: 1;
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
padding: 0.25rem;
|
|
|
|
|
}
|
|
|
|
|
.cl-item {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
gap: 0.5rem;
|
|
|
|
|
padding: 0.5rem 0.5rem;
|
|
|
|
|
border-radius: 0.375rem;
|
|
|
|
|
transition: background 0.15s;
|
|
|
|
|
border-bottom: 1px solid rgba(51,65,85,0.4);
|
|
|
|
|
}
|
|
|
|
|
.cl-item:hover { background: rgba(51,65,85,0.3); }
|
|
|
|
|
.cl-dot {
|
|
|
|
|
width: 8px; height: 8px;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
margin-top: 0.35rem;
|
|
|
|
|
}
|
|
|
|
|
.cl-info { flex: 1; min-width: 0; }
|
|
|
|
|
.cl-name { font-size: 0.82rem; font-weight: 600; color: #f1f5f9; }
|
|
|
|
|
.cl-meta { font-size: 0.72rem; color: #94a3b8; }
|
|
|
|
|
.cl-woven { color: #8b5cf6; font-weight: 600; }
|
|
|
|
|
.cl-desc { font-size: 0.72rem; color: #64748b; margin-top: 0.15rem; line-height: 1.4; }
|
|
|
|
|
|
|
|
|
|
/* Pool panel (right side) — visualization */
|
|
|
|
|
.pool-panel {
|
|
|
|
|
flex: 1;
|
|
|
|
|
background: #0f172a;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
.pool-panel-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
padding: 0.5rem 0.75rem;
|
|
|
|
|
font-size: 0.82rem;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #94a3b8;
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
letter-spacing: 0.04em;
|
|
|
|
|
border-bottom: 1px solid #334155;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
background: #1e293b;
|
|
|
|
|
}
|
|
|
|
|
.weave-toggle-btn {
|
|
|
|
|
background: none; border: 1px solid #475569; border-radius: 0.375rem;
|
|
|
|
|
color: #94a3b8; font-size: 0.78rem; cursor: pointer; padding: 0.25rem 0.6rem;
|
|
|
|
|
transition: all 0.15s; text-transform: none; letter-spacing: normal;
|
|
|
|
|
}
|
|
|
|
|
.weave-toggle-btn:hover { border-color: #8b5cf6; color: #e2e8f0; }
|
|
|
|
|
#pool-canvas { flex: 1; min-height: 0; display: block; cursor: default; touch-action: none; }
|
|
|
|
|
|
|
|
|
|
.pool-detail {
|
|
|
|
|
@ -3662,16 +3867,6 @@ const CSS_TEXT = `
|
|
|
|
|
background: rgba(139,92,246,0.1); border-radius: 0.25rem;
|
|
|
|
|
display: inline-block;
|
|
|
|
|
}
|
|
|
|
|
.pool-detail-drag-btn {
|
|
|
|
|
margin-top: 0.5rem; padding: 0.35rem 0.75rem; width: 100%;
|
|
|
|
|
background: linear-gradient(135deg, #8b5cf6, #ec4899);
|
|
|
|
|
color: #fff; border: none; border-radius: 0.375rem;
|
|
|
|
|
font-size: 0.78rem; font-weight: 600; cursor: grab;
|
|
|
|
|
transition: opacity 0.15s; touch-action: none;
|
|
|
|
|
}
|
|
|
|
|
.pool-detail-drag-btn:hover { opacity: 0.85; }
|
|
|
|
|
.pool-detail-drag-btn:active { cursor: grabbing; }
|
|
|
|
|
|
|
|
|
|
/* Pool header hint */
|
|
|
|
|
.pool-hint {
|
|
|
|
|
font-size: 0.68rem; font-weight: 400; color: #64748b;
|
|
|
|
|
@ -3709,21 +3904,7 @@ const CSS_TEXT = `
|
|
|
|
|
|
|
|
|
|
.pool-panel-sidebar { flex-shrink: 0; overflow-y: auto; max-height: 200px; border-top: 1px solid #334155; }
|
|
|
|
|
|
|
|
|
|
.add-btn {
|
|
|
|
|
padding: 0.5rem 0.75rem;
|
|
|
|
|
margin: 0.5rem;
|
|
|
|
|
background: linear-gradient(135deg, #8b5cf6, #ec4899);
|
|
|
|
|
color: #fff;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 0.5rem;
|
|
|
|
|
font-size: 0.82rem;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
box-shadow: 0 4px 16px rgba(139,92,246,0.3);
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
.add-btn:hover { transform: translateY(-1px); box-shadow: 0 6px 20px rgba(139,92,246,0.4); }
|
|
|
|
|
/* Legacy .add-btn kept for modal fallback */
|
|
|
|
|
|
|
|
|
|
.sidebar-item-info { flex: 1; min-width: 0; }
|
|
|
|
|
.sidebar-item-name { font-size: 0.82rem; font-weight: 600; color: #f1f5f9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
|
|
|
@ -4309,6 +4490,23 @@ const CSS_TEXT = `
|
|
|
|
|
:host([data-theme="light"]) .dep-port-diamond { fill: #e2e8f0; stroke: #94a3b8; }
|
|
|
|
|
:host([data-theme="light"]) .project-frame-rect { stroke: #8b5cf644; }
|
|
|
|
|
:host([data-theme="light"]) .pool-detail-woven { background: rgba(139,92,246,0.08); }
|
|
|
|
|
:host([data-theme="light"]) .form-panel { background: #fff; border-right-color: #e2e8f0; }
|
|
|
|
|
:host([data-theme="light"]) .form-panel-header { color: #64748b; border-bottom-color: #e2e8f0; }
|
|
|
|
|
:host([data-theme="light"]) .inline-form { border-bottom-color: #e2e8f0; }
|
|
|
|
|
:host([data-theme="light"]) .inline-form-field input,
|
|
|
|
|
:host([data-theme="light"]) .inline-form-field select { background: #f8fafc; border-color: #e2e8f0; color: #1e293b; }
|
|
|
|
|
:host([data-theme="light"]) .inline-form-field label { color: #64748b; }
|
|
|
|
|
:host([data-theme="light"]) .commitments-list-header { color: #94a3b8; border-bottom-color: #e2e8f0; }
|
|
|
|
|
:host([data-theme="light"]) .commitments-count { background: #e2e8f0; color: #64748b; }
|
|
|
|
|
:host([data-theme="light"]) .cl-item { border-bottom-color: rgba(226,232,240,0.4); }
|
|
|
|
|
:host([data-theme="light"]) .cl-item:hover { background: rgba(241,245,249,0.6); }
|
|
|
|
|
:host([data-theme="light"]) .cl-name { color: #1e293b; }
|
|
|
|
|
:host([data-theme="light"]) .cl-meta { color: #64748b; }
|
|
|
|
|
:host([data-theme="light"]) .cl-desc { color: #94a3b8; }
|
|
|
|
|
:host([data-theme="light"]) .pool-panel { background: #f8fafc; }
|
|
|
|
|
:host([data-theme="light"]) .weave-view-header { background: #fff; color: #64748b; border-bottom-color: #e2e8f0; }
|
|
|
|
|
:host([data-theme="light"]) .weave-back-btn { border-color: #e2e8f0; color: #64748b; }
|
|
|
|
|
:host([data-theme="light"]) .weave-toggle-btn { border-color: #e2e8f0; color: #64748b; }
|
|
|
|
|
|
|
|
|
|
/* Hex hover stroke */
|
|
|
|
|
.hex-hover-stroke { transition: stroke-width 0.15s; }
|
|
|
|
|
@ -4376,12 +4574,15 @@ const CSS_TEXT = `
|
|
|
|
|
.skill-legend { gap: 0.5rem; }
|
|
|
|
|
.skill-legend-item { font-size: 0.68rem; }
|
|
|
|
|
#canvas-view { flex-direction: column; }
|
|
|
|
|
.pool-panel {
|
|
|
|
|
.form-panel {
|
|
|
|
|
width: 100% !important; min-width: unset;
|
|
|
|
|
border-right: none; border-bottom: 1px solid #334155;
|
|
|
|
|
flex: 1; min-height: 0; max-height: none;
|
|
|
|
|
flex: 0 0 auto; max-height: 50%;
|
|
|
|
|
}
|
|
|
|
|
.pool-panel {
|
|
|
|
|
flex: 1; min-height: 0;
|
|
|
|
|
border-top: 1px solid #334155;
|
|
|
|
|
}
|
|
|
|
|
.pool-panel.collapsed { flex: 0 0 36px; min-height: 36px; max-height: 36px; }
|
|
|
|
|
.canvas-wrap {
|
|
|
|
|
flex: 1; min-height: 0;
|
|
|
|
|
border-top: 1px solid #334155;
|
|
|
|
|
@ -4389,13 +4590,13 @@ const CSS_TEXT = `
|
|
|
|
|
.canvas-wrap-header { display: flex; }
|
|
|
|
|
.panel-divider { display: none !important; }
|
|
|
|
|
.pool-hint { display: none; }
|
|
|
|
|
.pool-panel-sidebar { max-height: 80px; }
|
|
|
|
|
.exec-panel { width: 95vw; }
|
|
|
|
|
.task-edit-panel { width: 95vw; }
|
|
|
|
|
}
|
|
|
|
|
@media (max-width: 640px) {
|
|
|
|
|
.pool-legend-skills { display: none; }
|
|
|
|
|
.pool-panel.collapsed { width: 100% !important; }
|
|
|
|
|
.inline-form-field label { font-size: 0.68rem; }
|
|
|
|
|
.inline-form-field input, .inline-form-field select { font-size: 0.78rem; padding: 0.35rem 0.45rem; }
|
|
|
|
|
}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|