mdboard 2.1.0 → 2.1.2
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/index.html +29 -7
- package/package.json +1 -1
- package/src/core/yaml.js +43 -3
package/index.html
CHANGED
|
@@ -202,12 +202,16 @@ th.sorted .sort-arrow{opacity:1;color:var(--accent)}
|
|
|
202
202
|
/* ── Detail Panel — Notion-style ─────────────────────────── */
|
|
203
203
|
.panel-overlay{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:99;opacity:0;pointer-events:none;transition:opacity .2s}
|
|
204
204
|
.panel-overlay.open{opacity:1;pointer-events:auto}
|
|
205
|
-
.detail-panel{top: 1rem;right: 1rem;height: calc(100vh - 2rem);border-radius: var(--radius);position:fixed;width:600px;max-width:92vw;background:var(--bg);border-left:1px solid var(--border);z-index:100;transform:translateX(100%);transition:transform .25s ease;display:flex;flex-direction:column;overflow:hidden}
|
|
205
|
+
.detail-panel{top: 1rem;right: 1rem;height: calc(100vh - 2rem);border-radius: var(--radius);position:fixed;width:600px;max-width:92vw;background:var(--bg);border-left:1px solid var(--border);z-index:100;transform:translateX(100%);transition:transform .25s ease,top .25s ease,left .25s ease,right .25s ease,width .25s ease,height .25s ease;display:flex;flex-direction:column;overflow:hidden}
|
|
206
206
|
.detail-panel.open{transform:translateX(0)}
|
|
207
|
+
.detail-panel.expanded{top:1rem;left:50%;right:auto;width:1060px;height:calc(100vh - 2rem);border:1px solid var(--border);box-shadow:0 16px 48px rgba(0,0,0,.4)}
|
|
208
|
+
.detail-panel.expanded.open{transform:translateX(-50%)}
|
|
207
209
|
.panel-header{padding:12px 20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;flex-shrink:0;background:var(--surface)}
|
|
208
210
|
.panel-type{font-size:10px;padding:3px 8px;border-radius:var(--radius-sm);background:var(--accent-dim);color:var(--accent);font-weight:700;text-transform:uppercase;letter-spacing:.04em}
|
|
209
211
|
.panel-item-id{font-family:var(--mono);font-size:13px;color:var(--text2)}
|
|
210
|
-
.panel-
|
|
212
|
+
.panel-expand{margin-left:auto;background:none;border:none;color:var(--text2);cursor:pointer;padding:4px 8px;border-radius:var(--radius-sm);line-height:1;display:flex;align-items:center}
|
|
213
|
+
.panel-expand:hover{background:var(--surface2);color:var(--text)}
|
|
214
|
+
.panel-close{background:none;border:none;color:var(--text2);cursor:pointer;font-size:18px;padding:4px 8px;border-radius:var(--radius-sm);line-height:1}
|
|
211
215
|
.panel-close:hover{background:var(--surface2);color:var(--text)}
|
|
212
216
|
.panel-title-wrap{padding:20px 24px 8px;flex-shrink:0}
|
|
213
217
|
.panel-title-input{width:100%;font-size:28px;font-weight:700;background:transparent;border:none;color:var(--text);font-family:var(--font);outline:none;padding:0;line-height:1.3}
|
|
@@ -475,6 +479,7 @@ h4.ce-header{font-size:15px;line-height:1.4}
|
|
|
475
479
|
.header{padding:12px 16px}
|
|
476
480
|
.content{padding:16px}
|
|
477
481
|
.detail-panel{width:100%;max-width:100%}
|
|
482
|
+
.detail-panel.expanded{width:96vw;height:90vh}
|
|
478
483
|
.notes-sidebar{width:200px}
|
|
479
484
|
.notes-header-bar{padding:24px 24px 0}
|
|
480
485
|
.notes-editorjs-wrap{padding:12px 16px 24px}
|
|
@@ -2610,10 +2615,10 @@ async function deleteCurrentNote(id) {
|
|
|
2610
2615
|
/* ══════════════════════════════════════════════════════════════
|
|
2611
2616
|
PANEL — Dynamic detail panel from config
|
|
2612
2617
|
══════════════════════════════════════════════════════════════ */
|
|
2613
|
-
var panelState = { open: false, entityType: null, item: null, isCreate: false, editor: null };
|
|
2618
|
+
var panelState = { open: false, entityType: null, item: null, isCreate: false, editor: null, expanded: false };
|
|
2614
2619
|
|
|
2615
2620
|
async function openPanel(entityType, item) {
|
|
2616
|
-
panelState = { open: true, entityType: entityType, item: JSON.parse(JSON.stringify(item)), isCreate: false, editor: null };
|
|
2621
|
+
panelState = { open: true, entityType: entityType, item: JSON.parse(JSON.stringify(item)), isCreate: false, editor: null, expanded: false };
|
|
2617
2622
|
document.getElementById('detail-panel').classList.add('open');
|
|
2618
2623
|
document.getElementById('panel-overlay').classList.add('open');
|
|
2619
2624
|
|
|
@@ -2630,11 +2635,23 @@ async function openPanel(entityType, item) {
|
|
|
2630
2635
|
|
|
2631
2636
|
function closePanel() {
|
|
2632
2637
|
if (panelState.editor) { destroyEditor(panelState.editor); panelState.editor = null; }
|
|
2633
|
-
panelState = { open: false, entityType: null, item: null, isCreate: false, editor: null };
|
|
2634
|
-
document.getElementById('detail-panel').classList.remove('open');
|
|
2638
|
+
panelState = { open: false, entityType: null, item: null, isCreate: false, editor: null, expanded: false };
|
|
2639
|
+
document.getElementById('detail-panel').classList.remove('open', 'expanded');
|
|
2635
2640
|
document.getElementById('panel-overlay').classList.remove('open');
|
|
2636
2641
|
}
|
|
2637
2642
|
|
|
2643
|
+
function togglePanelExpand() {
|
|
2644
|
+
panelState.expanded = !panelState.expanded;
|
|
2645
|
+
document.getElementById('detail-panel').classList.toggle('expanded', panelState.expanded);
|
|
2646
|
+
var btn = document.getElementById('panel-expand-btn');
|
|
2647
|
+
if (btn) {
|
|
2648
|
+
btn.innerHTML = panelState.expanded
|
|
2649
|
+
? '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M14 6h-4V2M2 10h4v4M10 6l4.5-4.5M6 10L1.5 14.5"/></svg>'
|
|
2650
|
+
: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M10 2h4v4M6 14H2v-4M14 2L9.5 6.5M2 14l4.5-4.5"/></svg>';
|
|
2651
|
+
btn.title = panelState.expanded ? 'Collapse' : 'Expand';
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2638
2655
|
function openCreateDialog(entityType) {
|
|
2639
2656
|
var fields = getEntityFields(entityType);
|
|
2640
2657
|
var item = { _isNew: true, title: '' };
|
|
@@ -2659,7 +2676,7 @@ function openCreateDialog(entityType) {
|
|
|
2659
2676
|
}
|
|
2660
2677
|
}
|
|
2661
2678
|
|
|
2662
|
-
panelState = { open: true, entityType: entityType, item: item, isCreate: true, editor: null };
|
|
2679
|
+
panelState = { open: true, entityType: entityType, item: item, isCreate: true, editor: null, expanded: false };
|
|
2663
2680
|
renderPanel();
|
|
2664
2681
|
document.getElementById('detail-panel').classList.add('open');
|
|
2665
2682
|
document.getElementById('panel-overlay').classList.add('open');
|
|
@@ -2686,6 +2703,10 @@ function renderPanel() {
|
|
|
2686
2703
|
html += '<span class="pill" style="background:' + item._sourceColor + '20;color:' + item._sourceColor + ';font-size:10px">' + escHtml(item._sourceLabel || item._source) + '</span>';
|
|
2687
2704
|
}
|
|
2688
2705
|
|
|
2706
|
+
var expandIcon = panelState.expanded
|
|
2707
|
+
? '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M14 6h-4V2M2 10h4v4M10 6l4.5-4.5M6 10L1.5 14.5"/></svg>'
|
|
2708
|
+
: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M10 2h4v4M6 14H2v-4M14 2L9.5 6.5M2 14l4.5-4.5"/></svg>';
|
|
2709
|
+
html += '<button class="panel-expand" id="panel-expand-btn" title="' + (panelState.expanded ? 'Collapse' : 'Expand') + '">' + expandIcon + '</button>';
|
|
2689
2710
|
html += '<button class="panel-close" id="panel-close-btn">×</button></div>';
|
|
2690
2711
|
|
|
2691
2712
|
// ── Title ──
|
|
@@ -2772,6 +2793,7 @@ function renderPanel() {
|
|
|
2772
2793
|
|
|
2773
2794
|
// Event listeners
|
|
2774
2795
|
document.getElementById('panel-close-btn').addEventListener('click', closePanel);
|
|
2796
|
+
document.getElementById('panel-expand-btn').addEventListener('click', togglePanelExpand);
|
|
2775
2797
|
document.getElementById('panel-cancel-btn').addEventListener('click', closePanel);
|
|
2776
2798
|
var saveBtn = document.getElementById('panel-save-btn');
|
|
2777
2799
|
if (saveBtn) saveBtn.addEventListener('click', isCreate ? saveCreatePanel : savePanel);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mdboard",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "Git-based project management dashboard. Reads markdown files with YAML frontmatter and serves a visual kanban board, table, milestones, and metrics views.",
|
|
5
5
|
"main": "./src/server/server.js",
|
|
6
6
|
"bin": {
|
package/src/core/yaml.js
CHANGED
|
@@ -58,8 +58,21 @@ function parseYaml(text) {
|
|
|
58
58
|
continue;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
// Check for continuation lines (multiline plain scalar)
|
|
62
|
+
let fullValue = rawValue;
|
|
63
|
+
let j = i + 1;
|
|
64
|
+
while (j < lines.length) {
|
|
65
|
+
const nextLine = lines[j];
|
|
66
|
+
if (nextLine.match(/^\s/) && nextLine.trim() !== '' &&
|
|
67
|
+
!nextLine.match(/^\s+-\s/) && !nextLine.match(/^\s+\w[\w.-]*\s*:/)) {
|
|
68
|
+
fullValue += ' ' + nextLine.trim();
|
|
69
|
+
j++;
|
|
70
|
+
} else {
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
obj[key] = parseValue(fullValue);
|
|
75
|
+
i = j;
|
|
63
76
|
}
|
|
64
77
|
|
|
65
78
|
return obj;
|
|
@@ -99,6 +112,29 @@ function serializeValue(v) {
|
|
|
99
112
|
return String(v);
|
|
100
113
|
}
|
|
101
114
|
|
|
115
|
+
function wrapPlainScalar(text) {
|
|
116
|
+
// Normalize newlines to spaces
|
|
117
|
+
const normalized = text.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
|
|
118
|
+
const words = normalized.split(' ');
|
|
119
|
+
const lines = [];
|
|
120
|
+
let currentLine = '';
|
|
121
|
+
|
|
122
|
+
for (const word of words) {
|
|
123
|
+
if (currentLine === '') {
|
|
124
|
+
currentLine = word;
|
|
125
|
+
} else if (currentLine.length + 1 + word.length > 78) {
|
|
126
|
+
lines.push(currentLine);
|
|
127
|
+
currentLine = word;
|
|
128
|
+
} else {
|
|
129
|
+
currentLine += ' ' + word;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (currentLine) lines.push(currentLine);
|
|
133
|
+
|
|
134
|
+
// First line is bare, continuation lines indented with 2 spaces
|
|
135
|
+
return lines.map((l, i) => (i === 0 ? l : ' ' + l)).join('\n');
|
|
136
|
+
}
|
|
137
|
+
|
|
102
138
|
function serializeYaml(obj) {
|
|
103
139
|
const lines = [];
|
|
104
140
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -124,7 +160,11 @@ function serializeYaml(obj) {
|
|
|
124
160
|
}
|
|
125
161
|
}
|
|
126
162
|
} else {
|
|
127
|
-
|
|
163
|
+
if (typeof value === 'string' && (value.length > 80 || value.indexOf('\n') !== -1)) {
|
|
164
|
+
lines.push(key + ': ' + wrapPlainScalar(value));
|
|
165
|
+
} else {
|
|
166
|
+
lines.push(key + ': ' + serializeValue(value));
|
|
167
|
+
}
|
|
128
168
|
}
|
|
129
169
|
}
|
|
130
170
|
return lines.join('\n');
|