tmux-weblink 2.0.13 → 2.0.14

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.
@@ -1,12 +1,12 @@
1
- import{cssVarsStyle as b}from"../theme.js";import{escapeHtml as m}from"../html.js";import{notesDbScript as g}from"../notes-db.js";import{notesUtilsScript as u}from"../notes-utils.js";import{commandbarCSS as x,commandbarHTML as f,commandbarScript as v,commandbarButtonHTML as y}from"../commandbar.js";function L(t,a,e=!1,r=[]){const o=t==="__global__",i=o?"Global":t,s=o?"__global__":"session:"+t,d="/notes",l=o?"notes-global":"notes-session-"+t.replace(/[:\/\\]/g,"-"),c=JSON.stringify(s),p=JSON.stringify(`${l}.md`),n=m(i);return`<!DOCTYPE html>
1
+ import{cssVarsStyle as c}from"../theme.js";import{escapeHtml as p}from"../html.js";import{notesDbScript as b}from"../notes-db.js";import{notesUtilsScript as m}from"../notes-utils.js";function f(t,n){const e=t==="__global__",a=e?"Global":t,r=e?"__global__":"session:"+t,i="/notes",s=e?"notes-global":"notes-session-"+t.replace(/[:\/\\]/g,"-"),d=JSON.stringify(r),l=JSON.stringify(`${s}.md`),o=p(a);return`<!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
- <title>Notes - ${n} - tmux-web</title>
7
+ <title>Notes - ${o} - tmux-web</title>
8
8
  <style>
9
- ${b(a.shell)}
9
+ ${c(n.shell)}
10
10
  html, body { background: var(--page-bg); color: var(--page-fg); min-height: 100%; font-family: var(--font-mono); }
11
11
  .container { max-width: 720px; margin: 40px auto; padding: 0 20px; }
12
12
  .page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; }
@@ -53,16 +53,15 @@ import{cssVarsStyle as b}from"../theme.js";import{escapeHtml as m}from"../html.j
53
53
  .container { margin: 20px auto; padding: 0 16px; }
54
54
  #notes-editor { min-height: 300px; padding: 12px; }
55
55
  }
56
- ${e?x():""}
56
+
57
57
  </style>
58
58
  </head>
59
59
  <body>
60
60
  <div class="container">
61
61
  <div class="page-header">
62
62
  <div class="breadcrumb">
63
- <a href="${d}">Notes</a> <span>/</span> <span>${n}</span>
63
+ <a href="${i}">Notes</a> <span>/</span> <span>${o}</span>
64
64
  </div>
65
- ${e?y("Search"):""}
66
65
  </div>
67
66
  <div class="toolbar">
68
67
  <button id="notes-copy">Copy</button>
@@ -73,9 +72,9 @@ import{cssVarsStyle as b}from"../theme.js";import{escapeHtml as m}from"../html.j
73
72
  </div>
74
73
 
75
74
  <script type="module">
76
- const NOTES_SCOPE = ${c};
77
- ${g()}
78
- ${u()}
75
+ const NOTES_SCOPE = ${d};
76
+ ${b()}
77
+ ${m()}
79
78
 
80
79
  const notesEditor = document.getElementById('notes-editor');
81
80
  const copyBtn = document.getElementById('notes-copy');
@@ -143,16 +142,14 @@ exportBtn.addEventListener('click', () => {
143
142
  const blob = new Blob([notePlain], { type: 'text/markdown' });
144
143
  const a = document.createElement('a');
145
144
  a.href = URL.createObjectURL(blob);
146
- a.download = ${p};
145
+ a.download = ${l};
147
146
  a.click();
148
147
  URL.revokeObjectURL(a.href);
149
148
  });
150
149
 
151
150
  renderNote();
152
151
  </script>
153
- ${e?f():""}
154
152
  <script type="module">
155
- ${e?v(r,[]):""}
156
153
  </script>
157
154
  </body>
158
- </html>`}export{L as renderNotesPage};
155
+ </html>`}export{f as renderNotesPage};
@@ -1,4 +1,4 @@
1
- import{cssVarsStyle as d}from"../theme.js";import{commandbarCSS as l,commandbarHTML as p,commandbarScript as m}from"../commandbar.js";import{sharedLayoutCSS as u,sharedHeader as b,sharedSidebar as f,newSessionModalHTML as v,newSessionModalScript as x}from"../shared-layout.js";import{icon as o}from"../icons.js";function t(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function g(e){return`<article class="quick-item" data-id="${t(e.id)}">
1
+ import{cssVarsStyle as n}from"../theme.js";import{sharedLayoutCSS as c,sharedHeader as s,sharedSidebar as d,newSessionModalHTML as l,newSessionModalScript as p}from"../shared-layout.js";import{icon as a}from"../icons.js";function t(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function u(e){return`<article class="quick-item" data-id="${t(e.id)}">
2
2
  <div class="quick-card-head">
3
3
  <div>
4
4
  <div class="quick-title">${t(e.title)}</div>
@@ -6,16 +6,25 @@ import{cssVarsStyle as d}from"../theme.js";import{commandbarCSS as l,commandbarH
6
6
  </div>
7
7
  <div class="quick-icon-actions">
8
8
  <button class="quick-icon-btn quick-edit" type="button" title="Edit command" aria-label="Edit ${t(e.title)}">
9
- ${o("edit")}
9
+ ${a("edit")}
10
10
  </button>
11
11
  <button class="quick-icon-btn quick-delete" type="button" title="Delete command" aria-label="Delete ${t(e.title)}">
12
- ${o("delete")}
12
+ ${a("delete")}
13
13
  </button>
14
14
  </div>
15
15
  </div>
16
16
  <pre class="quick-command-preview"><code>${t(e.command)}</code></pre>
17
- </article>`}function y(e,a,r=!1,i=[]){const n=JSON.stringify(e).replace(/</g,"\\u003c"),c=e.length?e.map(g).join(`
18
- `):'<p class="empty">No quick commands yet. Add one below, then use it from the terminal commandbar.</p>',s=`
17
+ </article>`}function x(e,r){const o=JSON.stringify(e).replace(/</g,"\\u003c"),i=e.length?e.map(u).join(`
18
+ `):'<p class="empty">No quick commands yet. Add one below.</p>';return`<!DOCTYPE html>
19
+ <html lang="en">
20
+ <head>
21
+ <meta charset="UTF-8" />
22
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
23
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
24
+ <title>Quick Commands - tmux-web</title>
25
+ <style>
26
+ ${n(r.shell)}
27
+ ${c(`
19
28
  .intro {
20
29
  margin: 0 0 18px; color: var(--panel-muted); font-size: var(--text-sm); line-height: 1.6;
21
30
  }
@@ -155,27 +164,18 @@ import{cssVarsStyle as d}from"../theme.js";import{commandbarCSS as l,commandbarH
155
164
  .quick-card-head { flex-wrap: wrap; }
156
165
  .quick-icon-actions { width: 100%; justify-content: flex-end; }
157
166
  }
158
- ${r?l():""}`;return`<!DOCTYPE html>
159
- <html lang="en">
160
- <head>
161
- <meta charset="UTF-8" />
162
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
163
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
164
- <title>Quick Commands - tmux-web</title>
165
- <style>
166
- ${d(a.shell)}
167
- ${u(s)}
167
+ `)}
168
168
  </style>
169
169
  </head>
170
170
  <body>
171
171
 
172
- ${b({commandbarEnabled:r,title:"Quick Commands",themeTemplate:a.template})}
172
+ ${s({title:"Quick Commands",themeTemplate:r.template})}
173
173
 
174
174
  <div class="page-wrap">
175
175
  <div class="page-layout">
176
- ${f({activePage:"quickCommands",refreshHref:"/quick-commands"})}
176
+ ${d({activePage:"quickCommands",refreshHref:"/quick-commands"})}
177
177
  <main class="main-panel">
178
- <p class="intro">Configure reusable snippets that can be pasted into the active tmux pane from the terminal commandbar.</p>
178
+ <p class="intro">Configure reusable snippets that can be pasted into the active tmux pane.</p>
179
179
  <p class="quick-error" id="quick-error"></p>
180
180
 
181
181
  <h2 class="quick-section-title">Add Command</h2>
@@ -190,7 +190,7 @@ ${b({commandbarEnabled:r,title:"Quick Commands",themeTemplate:a.template})}
190
190
  </label>
191
191
  <label>
192
192
  <span>Description</span>
193
- <input name="description" type="text" placeholder="Optional context shown in the commandbar" autocomplete="off" />
193
+ <input name="description" type="text" placeholder="Optional description" autocomplete="off" />
194
194
  </label>
195
195
  <div class="quick-actions">
196
196
  <button class="quick-save" type="submit">Add Command</button>
@@ -198,18 +198,18 @@ ${b({commandbarEnabled:r,title:"Quick Commands",themeTemplate:a.template})}
198
198
  </form>
199
199
 
200
200
  <h2 class="quick-section-title">Configured</h2>
201
- <div id="quick-list">${c}</div>
201
+ <div id="quick-list">${i}</div>
202
202
  </main>
203
203
  </div>
204
204
  </div>
205
205
 
206
- ${v()}
206
+ ${l()}
207
207
  <div class="quick-drawer-backdrop" id="quick-edit-backdrop"></div>
208
208
  <aside class="quick-drawer" id="quick-edit-drawer" aria-hidden="true" aria-label="Edit quick command">
209
209
  <div class="quick-drawer-header">
210
210
  <div>
211
211
  <h2>Edit Command</h2>
212
- <p>Changes apply to the commandbar immediately after save.</p>
212
+
213
213
  </div>
214
214
  <button class="quick-drawer-close" id="quick-edit-close" type="button" aria-label="Close edit drawer">&times;</button>
215
215
  </div>
@@ -233,10 +233,9 @@ ${v()}
233
233
  </div>
234
234
  </form>
235
235
  </aside>
236
- ${r?p():""}
237
236
 
238
237
  <script type="module">
239
- const commands = ${n};
238
+ const commands = ${o};
240
239
  const errorEl = document.getElementById('quick-error');
241
240
  const editBackdrop = document.getElementById('quick-edit-backdrop');
242
241
  const editDrawer = document.getElementById('quick-edit-drawer');
@@ -354,8 +353,7 @@ document.addEventListener('keydown', (event) => {
354
353
  if (event.key === 'Escape' && editDrawer.classList.contains('open')) closeEditDrawer();
355
354
  });
356
355
 
357
- ${r?m(i,[]):""}
358
- ${x()}
356
+ ${p()}
359
357
  </script>
360
358
  </body>
361
- </html>`}export{y as renderQuickCommandsPage};
359
+ </html>`}export{x as renderQuickCommandsPage};
@@ -1,21 +1,21 @@
1
- import{cssVarsStyle as y}from"../theme.js";import{commandbarCSS as S,commandbarHTML as k,commandbarScript as $}from"../commandbar.js";import{notesDrawerCSS as E,notesDrawerHTML as L,notesDrawerScript as A}from"../notes-drawer.js";import{sharedLayoutCSS as B,sharedHeader as C,sharedSidebar as M,newSessionModalHTML as q,newSessionModalScript as I}from"../shared-layout.js";import{DELAY_INVALID_MESSAGE as D,DELAY_MAX_MESSAGE as R,MAX_SCHEDULE_MS as T,scheduleDelayParseScript as z}from"../schedule-delay.js";function t(s){return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function p(s){const n=new Date(s);return n.toLocaleDateString()+" "+n.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function N(s,n){return s.length?`<div class="task-list">${s.map(e=>`<div class="task">
1
+ import{cssVarsStyle as v}from"../theme.js";import{notesDrawerCSS as w,notesDrawerHTML as y,notesDrawerScript as S}from"../notes-drawer.js";import{sharedLayoutCSS as k,sharedHeader as $,sharedSidebar as E,newSessionModalHTML as L,newSessionModalScript as A}from"../shared-layout.js";import{DELAY_INVALID_MESSAGE as B,DELAY_MAX_MESSAGE as C,MAX_SCHEDULE_MS as M,scheduleDelayParseScript as q}from"../schedule-delay.js";function t(s){return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function d(s){const n=new Date(s);return n.toLocaleDateString()+" "+n.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function I(s,n){return s.length?`<div class="task-list">${s.map(e=>`<div class="task">
2
2
  <div class="task-row1">
3
3
  <span class="cmd">${t(e.text)}</span>
4
4
  <span class="status-pill status-${e.status}">${e.status}</span>
5
5
  </div>
6
6
  <div class="task-row2">
7
7
  <a class="trig-target" href="/s/${encodeURIComponent(e.sessionName)}?window=${e.windowIndex}">${t(e.sessionName)} &middot; win:${e.windowIndex}</a>
8
- <span class="meta">${t(p(e.triggeredAt))}</span>
8
+ <span class="meta">${t(d(e.triggeredAt))}</span>
9
9
  </div>${e.status==="error"&&e.error?`
10
10
  <div class="trig-error">${t(e.error)}</div>`:""}
11
11
  </div>`).join(`
12
- `)}</div>`:`<p class="empty">No tasks triggered in the last ${n} day${n===1?"":"s"}.</p>`}function G(s,n,c,e=7,i=!1,u=[]){const d=[...s].sort((r,o)=>r.fireAt-o.fireAt),l=new Map;for(const r of d){const o=l.get(r.sessionName);o?o.push(r):l.set(r.sessionName,[r])}const m=[...l.entries()].map(([r,o])=>{const w=o.map(a=>`<div class="task" data-id="${t(a.id)}">
12
+ `)}</div>`:`<p class="empty">No tasks triggered in the last ${n} day${n===1?"":"s"}.</p>`}function N(s,n,i,e=7){const l=[...s].sort((r,o)=>r.fireAt-o.fireAt),c=new Map;for(const r of l){const o=c.get(r.sessionName);o?o.push(r):c.set(r.sessionName,[r])}const p=[...c.entries()].map(([r,o])=>{const x=o.map(a=>`<div class="task" data-id="${t(a.id)}">
13
13
  <div class="task-row1">
14
14
  <span class="cmd">${t(a.text)}</span>
15
15
  <span class="countdown" data-fire-at="${a.fireAt}">\u2026</span>
16
16
  </div>
17
17
  <div class="task-row2">
18
- <span class="meta"><a class="win-link" href="/s/${encodeURIComponent(a.sessionName)}?window=${a.windowIndex}">win:${a.windowIndex}</a> &middot; fires ${t(p(a.fireAt))}</span>
18
+ <span class="meta"><a class="win-link" href="/s/${encodeURIComponent(a.sessionName)}?window=${a.windowIndex}">win:${a.windowIndex}</a> &middot; fires ${t(d(a.fireAt))}</span>
19
19
  <div style="display:flex;gap:4px;align-items:center;">
20
20
  <button class="reschedule-btn" data-id="${t(a.id)}">reschedule</button>
21
21
  <button class="cancel-btn" data-id="${t(a.id)}">cancel</button>
@@ -40,9 +40,9 @@ import{cssVarsStyle as y}from"../theme.js";import{commandbarCSS as S,commandbarH
40
40
  <span class="sname">${t(r)}</span>
41
41
  <span class="scount">${o.length}</span>
42
42
  </a>
43
- <div class="task-list">${w}</div>
43
+ <div class="task-list">${x}</div>
44
44
  </div>`}).join(`
45
- `),h=d.length?m:'<p class="empty" id="empty-msg">No scheduled tasks.</p>',f=N(n,e),g=T,b=D,x=R,v=`
45
+ `),u=l.length?p:'<p class="empty" id="empty-msg">No scheduled tasks.</p>',m=I(n,e),h=M,g=B,f=C,b=`
46
46
  .session-head {
47
47
  display: flex; align-items: center; gap: 8px; text-decoration: none;
48
48
  font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
@@ -154,8 +154,8 @@ import{cssVarsStyle as y}from"../theme.js";import{commandbarCSS as S,commandbarH
154
154
  .reschedule-input-row { flex-direction: column; align-items: stretch; }
155
155
  .reschedule-input-row button { align-self: flex-start; }
156
156
  }
157
- ${i?S():""}
158
- ${E()}`;return`<!DOCTYPE html>
157
+
158
+ ${w()}`;return`<!DOCTYPE html>
159
159
  <html lang="en">
160
160
  <head>
161
161
  <meta charset="UTF-8" />
@@ -163,45 +163,43 @@ import{cssVarsStyle as y}from"../theme.js";import{commandbarCSS as S,commandbarH
163
163
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
164
164
  <title>Scheduled tasks - tmux-web</title>
165
165
  <style>
166
- ${y(c.shell)}
167
- ${B(v)}
166
+ ${v(i.shell)}
167
+ ${k(b)}
168
168
  </style>
169
169
  </head>
170
170
  <body>
171
171
 
172
- ${C({commandbarEnabled:i,title:"Scheduled",themeTemplate:c.template})}
172
+ ${$({title:"Scheduled",themeTemplate:i.template})}
173
173
 
174
174
  <div class="page-wrap">
175
175
  <div class="page-layout">
176
- ${M({activePage:"schedule",refreshHref:"/schedule"})}
176
+ ${E({activePage:"schedule",refreshHref:"/schedule"})}
177
177
  <main class="main-panel">
178
178
  <div class="page-tab-bar">
179
179
  <button class="page-tab active" data-tab="upcoming">Upcoming</button>
180
180
  <button class="page-tab" data-tab="triggered">Recently Triggered</button>
181
181
  </div>
182
182
  <div class="tab-panel active" data-panel="upcoming">
183
- <div id="schedule-list">${h}</div>
183
+ <div id="schedule-list">${u}</div>
184
184
  </div>
185
185
  <div class="tab-panel" data-panel="triggered">
186
- ${f}
186
+ ${m}
187
187
  </div>
188
188
  </main>
189
189
  </div>
190
190
  </div>
191
191
 
192
- ${q()}
193
- ${i?k():""}
194
- ${L("Notes - Global")}
192
+ ${L()}
193
+ ${y("Notes - Global")}
195
194
 
196
195
  <script type="module">
197
- ${A("__global__")}
198
- ${i?$(u,[]):""}
199
- ${I()}
196
+ ${S("__global__")}
197
+ ${A()}
200
198
  </script>
201
199
 
202
200
  <script>
203
- const MAX_SCHEDULE_MS = ${g};
204
- ${z()}
201
+ const MAX_SCHEDULE_MS = ${h};
202
+ ${q()}
205
203
 
206
204
  // \u2500\u2500 Tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
207
205
  function activateTab(name) {
@@ -286,13 +284,13 @@ async function submitReschedule(id, delayStr) {
286
284
  const delayMs = parseDelay(delayStr !== undefined ? delayStr : input.value);
287
285
  if (!delayMs) {
288
286
  input.classList.add('error');
289
- errorEl.textContent = ${JSON.stringify(b)};
287
+ errorEl.textContent = ${JSON.stringify(g)};
290
288
  input.focus();
291
289
  return;
292
290
  }
293
291
  if (delayMs > MAX_SCHEDULE_MS) {
294
292
  input.classList.add('error');
295
- errorEl.textContent = ${JSON.stringify(x)};
293
+ errorEl.textContent = ${JSON.stringify(f)};
296
294
  input.focus();
297
295
  return;
298
296
  }
@@ -389,4 +387,4 @@ tick();
389
387
  setInterval(tick, 1000);
390
388
  </script>
391
389
  </body>
392
- </html>`}export{G as renderScheduleIndex};
390
+ </html>`}export{N as renderScheduleIndex};
@@ -1,4 +1,4 @@
1
- import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_TEMPLATE_IDS as x}from"../themes/index.js";function n(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function g(a,e){return`<!DOCTYPE html>
1
+ import{cssVarsStyle as u}from"../theme.js";import{getThemeTemplates as h,THEME_TEMPLATE_IDS as b}from"../themes/index.js";function n(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function m(a,e){return`<!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
@@ -6,7 +6,7 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
  <title>${n(a)} - tmux-web</title>
8
8
  <style>
9
- ${h(e.shell)}
9
+ ${u(e.shell)}
10
10
  html, body { background: var(--page-bg); color: var(--page-fg); min-height: 100%; font-family: var(--font-sans); }
11
11
  .container { max-width: 680px; margin: 80px auto; padding: 0 24px; }
12
12
  .page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 28px; }
@@ -87,7 +87,7 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
87
87
  .num-input { width: 100%; }
88
88
  }
89
89
  </style>
90
- </head>`}function f(a,e){let r="";return a&&(r+='<div class="saved-flash">\u2713 Saved. Restart tmux-web to apply.</div>'),e&&(r+=`<div class="error-flash">${n(e)}</div>`),r}function T(a){const{settings:e,renderer:r,rendererOverridden:i,theme:l,plugins:t,saved:d=!1,error:s}=a,c=e.commandbar===!0,o=e.terminalRenderer??"xterm",m=e.defaultView??"default",v=e.scheduleHistoryDays??7,u=t.length?t.map(p=>`<div class="plugin-row">
90
+ </head>`}function x(a,e){let r="";return a&&(r+='<div class="saved-flash">\u2713 Saved. Restart tmux-web to apply.</div>'),e&&(r+=`<div class="error-flash">${n(e)}</div>`),r}function $(a){const{settings:e,renderer:r,rendererOverridden:l,theme:d,plugins:t,saved:c=!1,error:s}=a,i=e.terminalRenderer??"xterm",o=e.defaultView??"default",g=e.scheduleHistoryDays??7,v=t.length?t.map(p=>`<div class="plugin-row">
91
91
  <span class="pkg">${n(p)}</span>
92
92
  <form method="POST" action="/settings/plugins" onsubmit="return confirm('Remove ${n(p)}?');">
93
93
  <input type="hidden" name="action" value="remove" />
@@ -95,7 +95,7 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
95
95
  <button type="submit" class="btn danger">Remove</button>
96
96
  </form>
97
97
  </div>`).join(`
98
- `):'<p class="desc" style="margin:0">No plugins enabled.</p>';return`${g("Settings",l)}
98
+ `):'<p class="desc" style="margin:0">No plugins enabled.</p>';return`${m("Settings",d)}
99
99
  <body>
100
100
  <div class="container">
101
101
  <div class="page-header">
@@ -108,38 +108,32 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
108
108
  <strong>restart the tmux-web process</strong> after making changes for them to take effect.
109
109
  </div>
110
110
 
111
- ${f(d,s)}
111
+ ${x(c,s)}
112
112
 
113
113
  <form method="POST" action="/settings">
114
- <div class="section">
115
- <h2>Command bar</h2>
116
- <p class="desc">\u2318K session search + quick actions.</p>
117
- <label class="row"><input type="checkbox" name="commandbar" ${c?"checked":""} /> Enable command bar</label>
118
- </div>
119
-
120
114
  <div class="section">
121
115
  <h2>Terminal library</h2>
122
116
  <p class="desc">Rendering engine for the terminal view.</p>
123
117
  <div class="radios">
124
- <label class="row"><input type="radio" name="terminalRenderer" value="xterm" ${o==="xterm"?"checked":""} /> xterm.js (default)</label>
125
- <label class="row"><input type="radio" name="terminalRenderer" value="ghostty" ${o==="ghostty"?"checked":""} /> ghostty-web</label>
118
+ <label class="row"><input type="radio" name="terminalRenderer" value="xterm" ${i==="xterm"?"checked":""} /> xterm.js (default)</label>
119
+ <label class="row"><input type="radio" name="terminalRenderer" value="ghostty" ${i==="ghostty"?"checked":""} /> ghostty-web</label>
126
120
  </div>
127
- ${i?`<p class="override-note">\u26A0 A CLI flag or <code>TMUX_WEB_TERMINAL_RENDERER</code> env var is currently forcing <strong>${r}</strong>, overriding this setting for the running process.</p>`:""}
121
+ ${l?`<p class="override-note">\u26A0 A CLI flag or <code>TMUX_WEB_TERMINAL_RENDERER</code> env var is currently forcing <strong>${r}</strong>, overriding this setting for the running process.</p>`:""}
128
122
  </div>
129
123
 
130
124
  <div class="section">
131
125
  <h2>Default home tab</h2>
132
126
  <p class="desc">Which tab the home page opens on.</p>
133
127
  <div class="radios">
134
- <label class="row"><input type="radio" name="defaultView" value="default" ${m==="default"?"checked":""} /> Default</label>
135
- <label class="row"><input type="radio" name="defaultView" value="recent" ${m==="recent"?"checked":""} /> Last Updated</label>
128
+ <label class="row"><input type="radio" name="defaultView" value="default" ${o==="default"?"checked":""} /> Default</label>
129
+ <label class="row"><input type="radio" name="defaultView" value="recent" ${o==="recent"?"checked":""} /> Last Updated</label>
136
130
  </div>
137
131
  </div>
138
132
 
139
133
  <div class="section">
140
134
  <h2>Schedule history</h2>
141
135
  <p class="desc">Days to keep the <code>/schedule</code> "Recently Triggered" history (fired &amp; missed tasks). 1\u2013365, default 7.</p>
142
- <label class="row"><input type="number" class="num-input" name="scheduleHistoryDays" min="1" max="365" value="${v}" /> days</label>
136
+ <label class="row"><input type="number" class="num-input" name="scheduleHistoryDays" min="1" max="365" value="${g}" /> days</label>
143
137
  </div>
144
138
 
145
139
  <div class="form-actions">
@@ -150,7 +144,7 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
150
144
  <div class="section" style="margin-top:16px">
151
145
  <h2>Plugins</h2>
152
146
  <p class="desc">Installed via npm into the tmux-web data dir. Add/remove runs npm and may take a few seconds.</p>
153
- ${u}
147
+ ${v}
154
148
  <form method="POST" action="/settings/plugins" class="plugin-add">
155
149
  <input type="hidden" name="action" value="add" />
156
150
  <input type="text" id="pkg-input" name="pkg" placeholder="npm package name" autocomplete="off" />
@@ -171,14 +165,14 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
171
165
  </div>
172
166
  </div>
173
167
  </body>
174
- </html>`}const y={vscode:"VS Code",ghostty:"Ghostty","warm-clay":"Warm Clay","dark-cove":"Dark Cove"},w=["background","foreground","red","green","yellow","blue","magenta","cyan"];function S(a){const{theme:e,saved:r=!1}=a,i=b(),l=x.map(t=>{const d=i[t],s=e.template===t,c=w.map(o=>`<span class="swatch" style="background:${n(d.terminal[o])}" title="${o}"></span>`).join("");return`<label class="theme-card${s?" active":""}">
168
+ </html>`}const f={vscode:"VS Code",ghostty:"Ghostty","warm-clay":"Warm Clay","dark-cove":"Dark Cove"},y=["background","foreground","red","green","yellow","blue","magenta","cyan"];function T(a){const{theme:e,saved:r=!1}=a,l=h(),d=b.map(t=>{const c=l[t],s=e.template===t,i=y.map(o=>`<span class="swatch" style="background:${n(c.terminal[o])}" title="${o}"></span>`).join("");return`<label class="theme-card${s?" active":""}">
175
169
  <div class="tname">
176
170
  <input type="radio" name="template" value="${t}" ${s?"checked":""} style="accent-color:var(--panel-success)" />
177
- ${n(y[t]??t)}
171
+ ${n(f[t]??t)}
178
172
  </div>
179
- <div class="swatches">${c}</div>
173
+ <div class="swatches">${i}</div>
180
174
  </label>`}).join(`
181
- `);return`${g("Theme",e)}
175
+ `);return`${m("Theme",e)}
182
176
  <body>
183
177
  <div class="container">
184
178
  <div class="page-header">
@@ -194,7 +188,7 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
194
188
 
195
189
  <form method="POST" action="/settings/theme">
196
190
  <div class="theme-grid">
197
- ${l}
191
+ ${d}
198
192
  </div>
199
193
  <div class="form-actions" style="margin-top:16px">
200
194
  <button type="submit" class="btn primary">Save theme</button>
@@ -202,4 +196,4 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
202
196
  </form>
203
197
  </div>
204
198
  </body>
205
- </html>`}export{T as renderSettings,S as renderThemeSettings};
199
+ </html>`}export{$ as renderSettings,T as renderThemeSettings};
@@ -1,4 +1,4 @@
1
- import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarHTML as x,commandbarScript as m}from"../commandbar.js";import{newSessionModalCSS as v,newSessionModalHTML as u,newSessionModalScript as h,reducedMotion as y}from"../shared-layout.js";import{icon as i}from"../icons.js";function $(o){return o.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function n(o="var(--panel-accent)"){return`box-shadow: 0 0 0 2px ${o}; outline: none;`}function T(o){const{theme:e,commandbarEnabled:t,commandbarSessions:a,fsRoots:s,terminalCfg:p,renderer:r,scrollback:l,wsBase:d}=o,c=`
1
+ import{cssVarsStyle as c}from"../theme.js";import{newSessionModalCSS as f,newSessionModalHTML as g,newSessionModalScript as x,reducedMotion as b}from"../shared-layout.js";import{icon as i}from"../icons.js";function y(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function o(t="var(--panel-accent)"){return`box-shadow: 0 0 0 2px ${t}; outline: none;`}function k(t){const{theme:e,fsRoots:r,terminalCfg:a,renderer:n,scrollback:s,wsBase:p}=t,l=`
2
2
  *, *::before, *::after { box-sizing: border-box; }
3
3
  html, body {
4
4
  background: var(--page-bg); color: var(--page-fg);
@@ -87,7 +87,7 @@ import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarH
87
87
  }
88
88
  .sidebar-footer .mode-btn:hover { color: var(--panel-accent); background: color-mix(in srgb, var(--panel-accent) 8%, transparent); }
89
89
  .sidebar-footer .mode-btn.active { color: var(--panel-accent); background: color-mix(in srgb, var(--panel-accent) 10%, transparent); }
90
- .sidebar-footer .mode-btn:focus-visible { ${n()} }
90
+ .sidebar-footer .mode-btn:focus-visible { ${o()} }
91
91
 
92
92
  /* \u2500\u2500 Sidebar session mode \u2500\u2500 */
93
93
  .session-item {
@@ -109,7 +109,7 @@ import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarH
109
109
  }
110
110
  .session-item:hover .session-edit-btn { display: flex; align-items: center; }
111
111
  .session-edit-btn:hover { color: var(--panel-accent); background: color-mix(in srgb, var(--panel-accent) 8%, transparent); }
112
- .session-edit-btn:focus-visible { ${n()} }
112
+ .session-edit-btn:focus-visible { ${o()} }
113
113
 
114
114
  .sidebar-section-label {
115
115
  font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.05em;
@@ -135,7 +135,7 @@ import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarH
135
135
  color: var(--panel-accent); border-color: var(--panel-accent);
136
136
  background: color-mix(in srgb, var(--panel-accent) 6%, transparent);
137
137
  }
138
- .new-session-sidebar-btn:focus-visible { ${n()} }
138
+ .new-session-sidebar-btn:focus-visible { ${o()} }
139
139
  .new-session-sidebar-btn svg { width: 16px; height: 16px; fill: currentColor; }
140
140
 
141
141
  /* \u2500\u2500 Sidebar files mode \u2500\u2500 */
@@ -409,7 +409,7 @@ import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarH
409
409
  color: var(--page-fg); transition: opacity 0.15s; text-decoration: none;
410
410
  }
411
411
  .btn:hover { opacity: 0.85; }
412
- .btn:focus-visible { ${n()} }
412
+ .btn:focus-visible { ${o()} }
413
413
  .btn.primary { background: var(--panel-accent); border-color: var(--panel-accent); color: var(--panel-accent-on); font-weight: 500; }
414
414
  .btn.primary:hover { opacity: 0.9; }
415
415
  .btn.danger { color: #b91c1c; border-color: color-mix(in srgb, #b91c1c 30%, transparent); }
@@ -580,10 +580,8 @@ import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarH
580
580
  .file-roots-list li:hover { border-color: var(--panel-accent); }
581
581
  .file-roots-list li svg { width: 20px; height: 20px; flex-shrink: 0; fill: var(--panel-accent); }
582
582
 
583
- /* \u2500\u2500 Commandbar \u2500\u2500 */
584
- ${t?b():""}
585
- ${y()}
586
- ${v()}
583
+ ${b()}
584
+ ${f()}
587
585
  @media (max-width: 640px) {
588
586
  .app-layout { flex-direction: column; }
589
587
  .sidebar { flex: 0 0 auto; border-right: none; border-bottom: 1px solid var(--panel-border); transition: max-height 0.2s; }
@@ -594,7 +592,7 @@ import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarH
594
592
  .mobile-keys .mk-buttons { display: none; }
595
593
  .mobile-keys.mk-focused .mk-buttons { display: flex; flex-wrap: wrap; gap: 4px; }
596
594
  }
597
- `,k=JSON.stringify(e.terminal).replace(/</g,"\\u003c"),f=JSON.stringify({terminal:p,scrollback:l,theme:e.terminal,renderer:r,fsRoots:s,commandbarEnabled:t,wsBase:d||""}).replace(/</g,"\\u003c");return`<!DOCTYPE html>
595
+ `,m=JSON.stringify(e.terminal).replace(/</g,"\\u003c"),d=JSON.stringify({terminal:a,scrollback:s,theme:e.terminal,renderer:n,fsRoots:r,wsBase:p||""}).replace(/</g,"\\u003c");return`<!DOCTYPE html>
598
596
  <html lang="en">
599
597
  <head>
600
598
  <meta charset="UTF-8" />
@@ -607,8 +605,8 @@ import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarH
607
605
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
608
606
  <title>tmux-weblink</title>
609
607
  <style>
610
- ${g(e.shell)}
611
- ${c}
608
+ ${c(e.shell)}
609
+ ${l}
612
610
  </style>
613
611
  </head>
614
612
  <body>
@@ -633,7 +631,6 @@ import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarH
633
631
  <header class="fixed-header">
634
632
  <div class="brand" id="brand-toggle">tmux<span>-weblink</span></div>
635
633
  <div class="header-actions">
636
- ${t?`<button class="header-btn" id="cmdbar-btn" title="Search" aria-label="Search">${i("search")}</button>`:""}
637
634
  </div>
638
635
  <div id="header-git" title="Click to browse repository"></div>
639
636
  <span id="header-ram"></span>
@@ -703,16 +700,9 @@ import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarH
703
700
  <!-- Settings popover -->
704
701
  <div class="popover-backdrop" id="settings-backdrop"></div>
705
702
  <div class="settings-popover" id="settings-popover">
706
- <div class="settings-item">
707
- <span>Command bar</span>
708
- <button class="toggle${t?" on":""}" id="set-commandbar"></button>
709
- </div>
710
- <div class="settings-item">
711
- </div>
712
- <hr class="settings-divider" />
713
703
  <div class="settings-item">
714
704
  <span>Terminal renderer</span>
715
- <span style="font-size:var(--text-xs);color:var(--panel-muted)">${r==="ghostty"?"Ghostty":"xterm.js"}</span>
705
+ <span style="font-size:var(--text-xs);color:var(--panel-muted)">${n==="ghostty"?"Ghostty":"xterm.js"}</span>
716
706
  </div>
717
707
  <hr class="settings-divider" />
718
708
  <div style="padding:4px 0">
@@ -760,21 +750,19 @@ import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarH
760
750
  })();
761
751
  </script>
762
752
 
763
- ${u()}
764
- ${t?x():""}
753
+ ${g()}
765
754
 
766
755
  <script>
767
- window.__TMUX_WEB_SHELL__ = ${f};
756
+ window.__TMUX_WEB_SHELL__ = ${d};
768
757
  </script>
769
758
  <script type="module">
770
759
  await import('/assets/shell-client.js');
771
- ${t?m(a,[]):""}
772
760
  // Wrapper: refresh sidebar list, then open session
773
761
  window.__onSessionCreated = async function(name, agentId) {
774
762
  await window.__refreshSidebar();
775
763
  window.__openSession(name, agentId || undefined);
776
764
  };
777
- ${h("__onSessionCreated")}
765
+ ${x("__onSessionCreated")}
778
766
  </script>
779
767
  <script>
780
768
  // Sync app-layout height to visual viewport so mobile keyboard doesn't overlap
@@ -841,4 +829,4 @@ if ('serviceWorker' in navigator) {
841
829
  }
842
830
  </script>
843
831
  </body>
844
- </html>`}export{T as renderShell};
832
+ </html>`}export{k as renderShell};
@@ -1 +1 @@
1
- import{readSettings as e,writeSettings as n}from"./settings.js";const t=[{id:"commandbar",label:"Command bar",description:"\u2318K session search + quick actions",kind:"builtin",isEnabled:a=>a.commandbar===!0,async enable(){const a=await e();await n({...a,commandbar:!0}),console.log("\u2713 command bar enabled")},async disable(){const a=await e();await n({...a,commandbar:!1}),console.log("\u2713 command bar disabled")}},{id:"agents",label:"Agents page",description:"watch AI agents (Claude, Codex, OpenCode, Cursor) in recently-viewed panes",kind:"builtin",isEnabled:a=>a.agents===!0,async enable(){const a=await e();await n({...a,agents:!0}),console.log("\u2713 agents page enabled")},async disable(){const a=await e();await n({...a,agents:!1}),console.log("\u2713 agents page disabled")}}];export{t as SETUP_FEATURES};
1
+ import{readSettings as a,writeSettings as t}from"./settings.js";const s=[{id:"agents",label:"Agents page",description:"watch AI agents (Claude, Codex, OpenCode, Cursor) in recently-viewed panes",kind:"builtin",isEnabled:e=>e.agents===!0,async enable(){const e=await a();await t({...e,agents:!0}),console.log("\u2713 agents page enabled")},async disable(){const e=await a();await t({...e,agents:!1}),console.log("\u2713 agents page disabled")}}];export{s as SETUP_FEATURES};