mdboard 1.2.0 → 1.3.0

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.
@@ -0,0 +1,144 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>mdboard</title>
7
+ <style>
8
+ <!-- STYLES -->
9
+ </style>
10
+ <style id="dynamic-styles"></style>
11
+ <style id="theme-styles"></style>
12
+ <link id="custom-theme" rel="stylesheet" href="/mdboard.css">
13
+ </head>
14
+ <body>
15
+ <div class="app">
16
+ <!-- Source Rail (Discord/Slack style) -->
17
+ <nav class="source-rail" id="source-rail"></nav>
18
+
19
+ <!-- Sidebar -->
20
+ <aside class="sidebar">
21
+ <div class="sidebar-logo" id="sidebar-logo">
22
+ <span class="sidebar-logo-icon" id="sidebar-logo-icon">&#9632;</span>
23
+ <span class="sidebar-logo-text" id="sidebar-logo-text">mdboard</span>
24
+ </div>
25
+ <nav id="sidebar-nav">
26
+ <a href="#board" data-view="board" class="active">
27
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
28
+ <span>Board</span>
29
+ </a>
30
+ <a href="#table" data-view="table">
31
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
32
+ <span>Table</span>
33
+ </a>
34
+ <a href="#milestones" data-view="milestones">
35
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/></svg>
36
+ <span>Milestones</span>
37
+ </a>
38
+ <a href="#metrics" data-view="metrics">
39
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M18 20V10M12 20V4M6 20v-6"/></svg>
40
+ <span>Metrics</span>
41
+ </a>
42
+ <a href="#notes" data-view="notes">
43
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
44
+ <span>Notes</span>
45
+ </a>
46
+ </nav>
47
+ <div class="sidebar-settings" id="sidebar-settings">
48
+ <a href="#" id="settings-toggle">
49
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 01-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"/></svg>
50
+ <span>Settings</span>
51
+ </a>
52
+ </div>
53
+ <div class="sidebar-footer">mdboard</div>
54
+ </aside>
55
+
56
+ <div class="main">
57
+ <!-- Header -->
58
+ <header class="header">
59
+ <div class="header-section" id="h-milestone-wrap" style="display:none">
60
+ <span class="header-section-label">Milestone</span>
61
+ <span class="header-section-value" id="h-milestone-name"></span>
62
+ <div class="progress progress-accent"><div class="progress-fill" id="h-milestone-progress" style="width:0%"></div></div>
63
+ </div>
64
+ <div class="header-section" id="h-sprint-wrap" style="display:none">
65
+ <span class="header-section-label">Sprint</span>
66
+ <span class="header-section-value" id="h-sprint-name"></span>
67
+ <span style="font-size:11px;color:var(--text2)" id="h-sprint-days"></span>
68
+ </div>
69
+ <div id="h-stats"></div>
70
+ </header>
71
+
72
+ <!-- Content -->
73
+ <div class="content">
74
+ <div id="view-board" class="view active">
75
+ <div id="sprint-bar" style="display:none"></div>
76
+ <div id="board-filters" class="filter-bar"></div>
77
+ <div id="board"></div>
78
+ </div>
79
+ <div id="view-table" class="view">
80
+ <div id="table-controls" class="filter-bar"></div>
81
+ <div id="table-wrapper"></div>
82
+ </div>
83
+ <div id="view-milestones" class="view">
84
+ <div id="ms-filters" class="filter-bar"></div>
85
+ <div id="milestones-container"></div>
86
+ </div>
87
+ <div id="view-metrics" class="view">
88
+ <div id="metrics-container"></div>
89
+ </div>
90
+ <div id="view-overview" class="view">
91
+ <div id="overview-container"></div>
92
+ </div>
93
+ <div id="view-notes" class="view">
94
+ <div id="notes-container"></div>
95
+ </div>
96
+ </div>
97
+ </div>
98
+ </div>
99
+
100
+ <!-- Detail Panel -->
101
+ <div id="panel-overlay" class="panel-overlay"></div>
102
+ <div id="detail-panel" class="detail-panel"></div>
103
+
104
+ <!-- Settings Panel -->
105
+ <div id="settings-overlay" class="settings-overlay"></div>
106
+ <div id="settings-panel" class="settings-panel">
107
+ <div class="settings-header">
108
+ <h2>Settings</h2>
109
+ <button class="panel-close" id="settings-close">&times;</button>
110
+ </div>
111
+ <div class="settings-content">
112
+ <div class="settings-section">
113
+ <h3>Theme</h3>
114
+ <p id="settings-theme-info" class="settings-theme-info"></p>
115
+ <div id="theme-grid" class="theme-grid"></div>
116
+ </div>
117
+ </div>
118
+ <div class="settings-footer">
119
+ <label class="toggle-label">
120
+ <input type="checkbox" id="theme-default-toggle">
121
+ <span class="toggle-switch"></span>
122
+ <span>Set as default for all projects</span>
123
+ </label>
124
+ <button class="btn btn-primary" id="settings-save">Save</button>
125
+ </div>
126
+ </div>
127
+
128
+ <!-- History Modal -->
129
+ <div id="history-overlay" class="history-overlay"></div>
130
+ <div id="history-modal" class="history-modal"></div>
131
+
132
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@2/dist/editorjs.umd.js"></script>
133
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/header@latest/dist/header.umd.js"></script>
134
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/list@latest/dist/editorjs-list.umd.js"></script>
135
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/code@latest/dist/code.umd.js"></script>
136
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/quote@latest/dist/quote.umd.js"></script>
137
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/delimiter@latest/dist/delimiter.umd.js"></script>
138
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/marker@latest/dist/marker.umd.js"></script>
139
+ <script src="https://cdn.jsdelivr.net/npm/@editorjs/inline-code@latest/dist/inline-code.umd.js"></script>
140
+ <script>
141
+ <!-- SCRIPTS -->
142
+ </script>
143
+ </body>
144
+ </html>
@@ -0,0 +1,261 @@
1
+ /* ══════════════════════════════════════════════════════════════
2
+ THEMES — Predefined color themes for mdboard
3
+ ══════════════════════════════════════════════════════════════ */
4
+ var THEMES = {
5
+ 'default-dark': {
6
+ name: 'Default Dark', type: 'dark',
7
+ vars: {
8
+ bg:'#0A0A0B',surface:'#141415',surface2:'#1A1A1C',border:'#232326',border2:'#2E2E33',
9
+ text:'#E8E8ED',text2:'#8B8B93',text3:'#5A5A63',
10
+ accent:'#5B6EF5','accent-dim':'rgba(91,110,245,.15)',
11
+ success:'#2EA043','success-dim':'rgba(46,160,67,.15)',
12
+ warning:'#D4A72C','warning-dim':'rgba(212,167,44,.15)',
13
+ danger:'#DA3633','danger-dim':'rgba(218,54,51,.15)',
14
+ purple:'#8B5CF6','purple-dim':'rgba(139,92,246,.15)'
15
+ }
16
+ },
17
+ 'linear-dark': {
18
+ name: 'Linear Dark', type: 'dark',
19
+ vars: {
20
+ bg:'#101012',surface:'#1A1A1F',surface2:'#222228',border:'#2C2C35',border2:'#38384A',
21
+ text:'#E2E2E9',text2:'#8E8E9E',text3:'#5C5C6E',
22
+ accent:'#5E6AD2','accent-dim':'rgba(94,106,210,.15)',
23
+ success:'#4DA771','success-dim':'rgba(77,167,113,.15)',
24
+ warning:'#F2C94C','warning-dim':'rgba(242,201,76,.15)',
25
+ danger:'#EB5757','danger-dim':'rgba(235,87,87,.15)',
26
+ purple:'#BB87FC','purple-dim':'rgba(187,135,252,.15)'
27
+ }
28
+ },
29
+ 'linear-light': {
30
+ name: 'Linear Light', type: 'light',
31
+ vars: {
32
+ bg:'#F9F9FB',surface:'#FFFFFF',surface2:'#F0F0F4',border:'#E0E0E6',border2:'#D0D0D8',
33
+ text:'#1A1A2E',text2:'#6B6B80',text3:'#9090A0',
34
+ accent:'#5E6AD2','accent-dim':'rgba(94,106,210,.1)',
35
+ success:'#4DA771','success-dim':'rgba(77,167,113,.1)',
36
+ warning:'#D4A017','warning-dim':'rgba(212,160,23,.1)',
37
+ danger:'#EB5757','danger-dim':'rgba(235,87,87,.1)',
38
+ purple:'#9B6DD7','purple-dim':'rgba(155,109,215,.1)'
39
+ }
40
+ },
41
+ 'jira-dark': {
42
+ name: 'Jira Dark', type: 'dark',
43
+ vars: {
44
+ bg:'#0D1117',surface:'#161B22',surface2:'#1C2333',border:'#293040',border2:'#344050',
45
+ text:'#DEE4EC',text2:'#8C96A5',text3:'#5A6577',
46
+ accent:'#2684FF','accent-dim':'rgba(38,132,255,.15)',
47
+ success:'#36B37E','success-dim':'rgba(54,179,126,.15)',
48
+ warning:'#FFAB00','warning-dim':'rgba(255,171,0,.15)',
49
+ danger:'#FF5630','danger-dim':'rgba(255,86,48,.15)',
50
+ purple:'#6554C0','purple-dim':'rgba(101,84,192,.15)'
51
+ }
52
+ },
53
+ 'jira-light': {
54
+ name: 'Jira Light', type: 'light',
55
+ vars: {
56
+ bg:'#F4F5F7',surface:'#FFFFFF',surface2:'#EBECF0',border:'#DFE1E6',border2:'#C1C7D0',
57
+ text:'#172B4D',text2:'#6B778C',text3:'#97A0AF',
58
+ accent:'#0052CC','accent-dim':'rgba(0,82,204,.1)',
59
+ success:'#36B37E','success-dim':'rgba(54,179,126,.1)',
60
+ warning:'#FF991F','warning-dim':'rgba(255,153,31,.1)',
61
+ danger:'#FF5630','danger-dim':'rgba(255,86,48,.1)',
62
+ purple:'#6554C0','purple-dim':'rgba(101,84,192,.1)'
63
+ }
64
+ },
65
+ 'catppuccin-mocha': {
66
+ name: 'Catppuccin Mocha', type: 'dark',
67
+ vars: {
68
+ bg:'#1E1E2E',surface:'#262637',surface2:'#313244',border:'#3B3B52',border2:'#45475A',
69
+ text:'#CDD6F4',text2:'#A6ADC8',text3:'#6C7086',
70
+ accent:'#89B4FA','accent-dim':'rgba(137,180,250,.15)',
71
+ success:'#A6E3A1','success-dim':'rgba(166,227,161,.15)',
72
+ warning:'#F9E2AF','warning-dim':'rgba(249,226,175,.15)',
73
+ danger:'#F38BA8','danger-dim':'rgba(243,139,168,.15)',
74
+ purple:'#CBA6F7','purple-dim':'rgba(203,166,247,.15)'
75
+ }
76
+ },
77
+ 'catppuccin-latte': {
78
+ name: 'Catppuccin Latte', type: 'light',
79
+ vars: {
80
+ bg:'#EFF1F5',surface:'#FFFFFF',surface2:'#E6E9EF',border:'#CCD0DA',border2:'#BCC0CC',
81
+ text:'#4C4F69',text2:'#6C6F85',text3:'#9CA0B0',
82
+ accent:'#1E66F5','accent-dim':'rgba(30,102,245,.1)',
83
+ success:'#40A02B','success-dim':'rgba(64,160,43,.1)',
84
+ warning:'#DF8E1D','warning-dim':'rgba(223,142,29,.1)',
85
+ danger:'#D20F39','danger-dim':'rgba(210,15,57,.1)',
86
+ purple:'#8839EF','purple-dim':'rgba(136,57,239,.1)'
87
+ }
88
+ },
89
+ 'ayu-dark': {
90
+ name: 'Ayu Dark', type: 'dark',
91
+ vars: {
92
+ bg:'#0B0E14',surface:'#0F1219',surface2:'#151920',border:'#1E222A',border2:'#272D38',
93
+ text:'#BFBDB6',text2:'#6C7380',text3:'#4A5060',
94
+ accent:'#E6B450','accent-dim':'rgba(230,180,80,.15)',
95
+ success:'#7FD962','success-dim':'rgba(127,217,98,.15)',
96
+ warning:'#FFB454','warning-dim':'rgba(255,180,84,.15)',
97
+ danger:'#F07178','danger-dim':'rgba(240,113,120,.15)',
98
+ purple:'#D2A6FF','purple-dim':'rgba(210,166,255,.15)'
99
+ }
100
+ },
101
+ 'ayu-light': {
102
+ name: 'Ayu Light', type: 'light',
103
+ vars: {
104
+ bg:'#F8F9FA',surface:'#FFFFFF',surface2:'#F0F1F2',border:'#E0E1E2',border2:'#D4D5D6',
105
+ text:'#5C6166',text2:'#787B80',text3:'#ACB0B5',
106
+ accent:'#FF9940','accent-dim':'rgba(255,153,64,.1)',
107
+ success:'#6CBF43','success-dim':'rgba(108,191,67,.1)',
108
+ warning:'#F2AE49','warning-dim':'rgba(242,174,73,.1)',
109
+ danger:'#F07171','danger-dim':'rgba(240,113,113,.1)',
110
+ purple:'#A37ACC','purple-dim':'rgba(163,122,204,.1)'
111
+ }
112
+ },
113
+ 'tokyo-night': {
114
+ name: 'Tokyo Night', type: 'dark',
115
+ vars: {
116
+ bg:'#1A1B26',surface:'#1F2335',surface2:'#24283B',border:'#2F3449',border2:'#3B4261',
117
+ text:'#C0CAF5',text2:'#7982A9',text3:'#565F89',
118
+ accent:'#7AA2F7','accent-dim':'rgba(122,162,247,.15)',
119
+ success:'#9ECE6A','success-dim':'rgba(158,206,106,.15)',
120
+ warning:'#E0AF68','warning-dim':'rgba(224,175,104,.15)',
121
+ danger:'#F7768E','danger-dim':'rgba(247,118,142,.15)',
122
+ purple:'#BB9AF7','purple-dim':'rgba(187,154,247,.15)'
123
+ }
124
+ },
125
+ 'tokyo-night-storm': {
126
+ name: 'Tokyo Night Storm', type: 'dark',
127
+ vars: {
128
+ bg:'#24283B',surface:'#292E42',surface2:'#2F3549',border:'#3B4261',border2:'#464F78',
129
+ text:'#C0CAF5',text2:'#7982A9',text3:'#565F89',
130
+ accent:'#7AA2F7','accent-dim':'rgba(122,162,247,.15)',
131
+ success:'#9ECE6A','success-dim':'rgba(158,206,106,.15)',
132
+ warning:'#E0AF68','warning-dim':'rgba(224,175,104,.15)',
133
+ danger:'#F7768E','danger-dim':'rgba(247,118,142,.15)',
134
+ purple:'#BB9AF7','purple-dim':'rgba(187,154,247,.15)'
135
+ }
136
+ },
137
+ 'notion-light': {
138
+ name: 'Notion Light', type: 'light',
139
+ vars: {
140
+ bg:'#F7F6F3',surface:'#FFFFFF',surface2:'#EEEEEC',border:'#E3E2DE',border2:'#D4D3CF',
141
+ text:'#37352F',text2:'#6B6B6B',text3:'#9B9A97',
142
+ accent:'#2383E2','accent-dim':'rgba(35,131,226,.1)',
143
+ success:'#0F7B0F','success-dim':'rgba(15,123,15,.1)',
144
+ warning:'#CB7B00','warning-dim':'rgba(203,123,0,.1)',
145
+ danger:'#E03E3E','danger-dim':'rgba(224,62,62,.1)',
146
+ purple:'#6940A5','purple-dim':'rgba(105,64,165,.1)'
147
+ }
148
+ },
149
+ 'notion-dark': {
150
+ name: 'Notion Dark', type: 'dark',
151
+ vars: {
152
+ bg:'#191919',surface:'#202020',surface2:'#2B2B2B',border:'#363636',border2:'#444444',
153
+ text:'#E3E2DE',text2:'#9B9B9B',text3:'#6B6B6B',
154
+ accent:'#529CCA','accent-dim':'rgba(82,156,202,.15)',
155
+ success:'#4DAB9A','success-dim':'rgba(77,171,154,.15)',
156
+ warning:'#CB7B00','warning-dim':'rgba(203,123,0,.15)',
157
+ danger:'#E03E3E','danger-dim':'rgba(224,62,62,.15)',
158
+ purple:'#9A6DD7','purple-dim':'rgba(154,109,215,.15)'
159
+ }
160
+ },
161
+ 'github-dark': {
162
+ name: 'GitHub Dark', type: 'dark',
163
+ vars: {
164
+ bg:'#0D1117',surface:'#161B22',surface2:'#1C2128',border:'#30363D',border2:'#3D444D',
165
+ text:'#E6EDF3',text2:'#8B949E',text3:'#6E7681',
166
+ accent:'#58A6FF','accent-dim':'rgba(88,166,255,.15)',
167
+ success:'#3FB950','success-dim':'rgba(63,185,80,.15)',
168
+ warning:'#D29922','warning-dim':'rgba(210,153,34,.15)',
169
+ danger:'#F85149','danger-dim':'rgba(248,81,73,.15)',
170
+ purple:'#BC8CFF','purple-dim':'rgba(188,140,255,.15)'
171
+ }
172
+ },
173
+ 'github-light': {
174
+ name: 'GitHub Light', type: 'light',
175
+ vars: {
176
+ bg:'#F6F8FA',surface:'#FFFFFF',surface2:'#EAEEF2',border:'#D0D7DE',border2:'#BCC3CB',
177
+ text:'#1F2328',text2:'#656D76',text3:'#8C959F',
178
+ accent:'#0969DA','accent-dim':'rgba(9,105,218,.1)',
179
+ success:'#1A7F37','success-dim':'rgba(26,127,55,.1)',
180
+ warning:'#9A6700','warning-dim':'rgba(154,103,0,.1)',
181
+ danger:'#CF222E','danger-dim':'rgba(207,34,46,.1)',
182
+ purple:'#8250DF','purple-dim':'rgba(130,80,223,.1)'
183
+ }
184
+ },
185
+ 'dracula': {
186
+ name: 'Dracula', type: 'dark',
187
+ vars: {
188
+ bg:'#1E1F29',surface:'#282A36',surface2:'#2E303E',border:'#3A3C4E',border2:'#44475A',
189
+ text:'#F8F8F2',text2:'#ADB0C0',text3:'#6272A4',
190
+ accent:'#BD93F9','accent-dim':'rgba(189,147,249,.15)',
191
+ success:'#50FA7B','success-dim':'rgba(80,250,123,.15)',
192
+ warning:'#F1FA8C','warning-dim':'rgba(241,250,140,.15)',
193
+ danger:'#FF5555','danger-dim':'rgba(255,85,85,.15)',
194
+ purple:'#FF79C6','purple-dim':'rgba(255,121,198,.15)'
195
+ }
196
+ },
197
+ 'nord': {
198
+ name: 'Nord', type: 'dark',
199
+ vars: {
200
+ bg:'#242933',surface:'#2E3440',surface2:'#353C4A',border:'#3B4252',border2:'#434C5E',
201
+ text:'#ECEFF4',text2:'#A5B1C2',text3:'#697688',
202
+ accent:'#88C0D0','accent-dim':'rgba(136,192,208,.15)',
203
+ success:'#A3BE8C','success-dim':'rgba(163,190,140,.15)',
204
+ warning:'#EBCB8B','warning-dim':'rgba(235,203,139,.15)',
205
+ danger:'#BF616A','danger-dim':'rgba(191,97,106,.15)',
206
+ purple:'#B48EAD','purple-dim':'rgba(180,142,173,.15)'
207
+ }
208
+ },
209
+ 'solarized-dark': {
210
+ name: 'Solarized Dark', type: 'dark',
211
+ vars: {
212
+ bg:'#002129',surface:'#002B36',surface2:'#073642',border:'#0A4050',border2:'#1A5060',
213
+ text:'#93A1A1',text2:'#839496',text3:'#586E75',
214
+ accent:'#268BD2','accent-dim':'rgba(38,139,210,.15)',
215
+ success:'#859900','success-dim':'rgba(133,153,0,.15)',
216
+ warning:'#B58900','warning-dim':'rgba(181,137,0,.15)',
217
+ danger:'#DC322F','danger-dim':'rgba(220,50,47,.15)',
218
+ purple:'#6C71C4','purple-dim':'rgba(108,113,196,.15)'
219
+ }
220
+ },
221
+ 'solarized-light': {
222
+ name: 'Solarized Light', type: 'light',
223
+ vars: {
224
+ bg:'#FDF6E3',surface:'#FFFFFF',surface2:'#EEE8D5',border:'#DDD6C1',border2:'#C9C2AD',
225
+ text:'#586E75',text2:'#657B83',text3:'#93A1A1',
226
+ accent:'#268BD2','accent-dim':'rgba(38,139,210,.1)',
227
+ success:'#859900','success-dim':'rgba(133,153,0,.1)',
228
+ warning:'#B58900','warning-dim':'rgba(181,137,0,.1)',
229
+ danger:'#DC322F','danger-dim':'rgba(220,50,47,.1)',
230
+ purple:'#6C71C4','purple-dim':'rgba(108,113,196,.1)'
231
+ }
232
+ },
233
+ 'one-dark': {
234
+ name: 'One Dark', type: 'dark',
235
+ vars: {
236
+ bg:'#1E2127',surface:'#282C34',surface2:'#2C313C',border:'#3A3F4B',border2:'#4B5263',
237
+ text:'#ABB2BF',text2:'#7F848E',text3:'#5C6370',
238
+ accent:'#61AFEF','accent-dim':'rgba(97,175,239,.15)',
239
+ success:'#98C379','success-dim':'rgba(152,195,121,.15)',
240
+ warning:'#E5C07B','warning-dim':'rgba(229,192,123,.15)',
241
+ danger:'#E06C75','danger-dim':'rgba(224,108,117,.15)',
242
+ purple:'#C678DD','purple-dim':'rgba(198,120,221,.15)'
243
+ }
244
+ },
245
+ 'gruvbox-dark': {
246
+ name: 'Gruvbox Dark', type: 'dark',
247
+ vars: {
248
+ bg:'#1D2021',surface:'#282828',surface2:'#32302F',border:'#3C3836',border2:'#504945',
249
+ text:'#EBDBB2',text2:'#A89984',text3:'#7C6F64',
250
+ accent:'#FE8019','accent-dim':'rgba(254,128,25,.15)',
251
+ success:'#B8BB26','success-dim':'rgba(184,187,38,.15)',
252
+ warning:'#FABD2F','warning-dim':'rgba(250,189,47,.15)',
253
+ danger:'#FB4934','danger-dim':'rgba(251,73,52,.15)',
254
+ purple:'#D3869B','purple-dim':'rgba(211,134,155,.15)'
255
+ }
256
+ }
257
+ };
258
+
259
+ var THEME_LIST = Object.keys(THEMES).map(function(id) {
260
+ return { id: id, name: THEMES[id].name, type: THEMES[id].type };
261
+ });
@@ -0,0 +1,164 @@
1
+ /* ══════════════════════════════════════════════════════════════
2
+ WORKSPACE — Source switching & sidebar
3
+ ══════════════════════════════════════════════════════════════ */
4
+ function renderSidebarLogo() {
5
+ var p = D.project || {};
6
+ var logoEl = document.getElementById('sidebar-logo');
7
+ var iconEl = document.getElementById('sidebar-logo-icon');
8
+ var textEl = document.getElementById('sidebar-logo-text');
9
+
10
+ textEl.textContent = p.name || 'Project';
11
+
12
+ if (D.config && D.config.logo) {
13
+ var logoSrc = D.config.logo.startsWith('http') ? D.config.logo : '/logo';
14
+ iconEl.innerHTML = '<img src="' + escHtml(logoSrc) + '" alt="">';
15
+ } else {
16
+ var initial = (p.name || 'P').charAt(0).toUpperCase();
17
+ iconEl.textContent = initial;
18
+ }
19
+
20
+ logoEl.onclick = function() {
21
+ if (hasWorkspace()) {
22
+ switchSource('overview');
23
+ }
24
+ };
25
+ }
26
+
27
+ function buildSourceRail() {
28
+ var rail = document.getElementById('source-rail');
29
+ if (!rail) return;
30
+ rail.innerHTML = '';
31
+
32
+ if (!hasWorkspace()) return;
33
+
34
+ // Home icon (overview)
35
+ var home = document.createElement('div');
36
+ home.className = 'rail-icon' + (D.activeSource === 'overview' ? ' active' : '');
37
+ home.dataset.source = 'overview';
38
+ home.setAttribute('data-tooltip', 'Overview');
39
+ home.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>';
40
+ home.onclick = function() { switchSource('overview'); };
41
+ rail.appendChild(home);
42
+
43
+ // Divider
44
+ var divider = document.createElement('div');
45
+ divider.className = 'rail-divider';
46
+ rail.appendChild(divider);
47
+
48
+ // Source icons
49
+ var wsSources = D.config.workspace.sources;
50
+ for (var i = 0; i < wsSources.length; i++) {
51
+ var s = wsSources[i];
52
+ if (s.name === 'overview') continue;
53
+
54
+ var color = s.color || 'var(--accent)';
55
+ var icon = document.createElement('div');
56
+ icon.className = 'rail-icon' + (D.activeSource === s.name ? ' active' : '');
57
+ icon.dataset.source = s.name;
58
+ icon.setAttribute('data-tooltip', s.label || s.name);
59
+ icon.style.background = color + '20';
60
+ icon.style.color = color;
61
+ icon.innerHTML = escHtml(s.icon || s.name.charAt(0).toUpperCase());
62
+ icon.onclick = (function(name) {
63
+ return function() { switchSource(name); };
64
+ })(s.name);
65
+ rail.appendChild(icon);
66
+ }
67
+
68
+ // Switch project icon (bottom of rail)
69
+ var switchDivider = document.createElement('div');
70
+ switchDivider.className = 'rail-divider';
71
+ switchDivider.style.marginTop = 'auto';
72
+ rail.appendChild(switchDivider);
73
+
74
+ var switchIcon = document.createElement('div');
75
+ switchIcon.className = 'rail-icon rail-switch';
76
+ switchIcon.setAttribute('data-tooltip', 'Switch workspace');
77
+ switchIcon.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 3h5v5"/><path d="M21 3l-7 7"/><path d="M8 21H3v-5"/><path d="M3 21l7-7"/></svg>';
78
+ switchIcon.onclick = function() { openHistoryModal(); };
79
+ rail.appendChild(switchIcon);
80
+ }
81
+
82
+ function switchSource(sourceName) {
83
+ if (sourceName === D.activeSource) return;
84
+
85
+ // Update active source marker
86
+ D.activeSource = sourceName;
87
+ D.loaded = false;
88
+
89
+ // Persist selection
90
+ try { localStorage.setItem('mdboard-source', sourceName); } catch(e) {}
91
+
92
+ // Update source rail active state
93
+ document.querySelectorAll('.rail-icon').forEach(function(el) {
94
+ el.classList.toggle('active', el.dataset.source === sourceName);
95
+ });
96
+
97
+ // If switching to overview, show overview tabs; otherwise show normal tabs
98
+ var isOverview = sourceName === 'overview';
99
+ var viewTabs = document.querySelectorAll('#sidebar-nav a[data-view]');
100
+ viewTabs.forEach(function(tab) {
101
+ var view = tab.dataset.view;
102
+ if (isOverview) {
103
+ tab.style.display = (view === 'overview' || view === 'metrics') ? '' : 'none';
104
+ } else {
105
+ tab.style.display = (view === 'overview') ? 'none' : '';
106
+ }
107
+ });
108
+
109
+ // Switch to appropriate view
110
+ if (isOverview) {
111
+ switchView('overview');
112
+ } else {
113
+ var currentView = document.querySelector('.view.active');
114
+ if (currentView && currentView.id === 'view-overview') {
115
+ switchView('board');
116
+ }
117
+ }
118
+
119
+ // Reload data for this source
120
+ loadAll().then(function() {
121
+ initFromConfig();
122
+ renderAll();
123
+ buildSourceRail();
124
+ });
125
+ }
126
+
127
+ /* ── SSE — Hot Reload ────────────────────────────────────── */
128
+ function connectSSE() {
129
+ try {
130
+ var src = new EventSource('/api/events');
131
+ src.onmessage = function(e) {
132
+ var data;
133
+ try { data = JSON.parse(e.data); } catch { data = {}; }
134
+
135
+ if (data.type === 'project-changed') {
136
+ // Full reload on project switch (from another tab or API call)
137
+ D.activeSource = null;
138
+ D.loaded = false;
139
+ loadAll().then(function() {
140
+ initFromConfig();
141
+ if (hasWorkspace()) {
142
+ buildSourceRail();
143
+ D.activeSource = null;
144
+ switchSource('overview');
145
+ } else {
146
+ // Hide source rail if no workspace
147
+ var rail = document.getElementById('source-rail');
148
+ if (rail) rail.innerHTML = '';
149
+ renderAll();
150
+ }
151
+ renderSidebarLogo();
152
+ });
153
+ return;
154
+ }
155
+
156
+ if (data.cssReload) {
157
+ var link = document.getElementById('custom-theme');
158
+ if (link) link.href = '/mdboard.css?' + Date.now();
159
+ }
160
+ refreshData();
161
+ };
162
+ src.onerror = function() { setTimeout(connectSSE, 5000); src.close(); };
163
+ } catch { /* no SSE support */ }
164
+ }