tmux-weblink 2.0.13 → 2.0.15

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,9 +1,9 @@
1
- import{cssVarsStyle as b}from"../theme.js";import{commandbarCSS as x,commandbarHTML as f,commandbarScript as h}from"../commandbar.js";import{notesDrawerCSS as u,notesDrawerHTML as w,notesDrawerScript as S}from"../notes-drawer.js";import{sharedLayoutCSS as $,sharedHeader as y,sharedSidebar as _,newSessionModalHTML as k,newSessionModalScript as D}from"../shared-layout.js";function s(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function T(t){const o=new Date(t);return o.toLocaleDateString()+" "+o.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function M(t,o,r=!1,i=[]){const n=[...t].sort((e,a)=>(a.updatedAt??0)-(e.updatedAt??0)),l=n.map(e=>{const a=e.scope==="__global__",d=a?"Global":e.scope.replace(/^session:/,""),m=a?"/notes/__global__":"/notes/"+encodeURIComponent(e.scope.replace(/^session:/,"")),v=s((e.content||"").slice(0,200).trim()||"No content"),g=s(T(e.updatedAt));return`<a class="note-card" href="${m}">
2
- <div class="label ${a?"global":""}">${s(d)}</div>
3
- <div class="preview">${v}</div>
4
- <div class="meta"><span>${g}</span></div>
1
+ import{cssVarsStyle as b}from"../theme.js";import{notesDrawerCSS as v,notesDrawerHTML as g,notesDrawerScript as x}from"../notes-drawer.js";import{sharedLayoutCSS as h,sharedHeader as f,sharedSidebar as u,newSessionModalHTML as w,newSessionModalScript as y}from"../shared-layout.js";function r(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function S(t){const a=new Date(t);return a.toLocaleDateString()+" "+a.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function D(t,a){const n=[...t].sort((e,o)=>(o.updatedAt??0)-(e.updatedAt??0)),s=n.map(e=>{const o=e.scope==="__global__",c=o?"Global":e.scope.replace(/^session:/,""),p=o?"/notes/__global__":"/notes/"+encodeURIComponent(e.scope.replace(/^session:/,"")),d=r((e.content||"").slice(0,200).trim()||"No content"),m=r(S(e.updatedAt));return`<a class="note-card" href="${p}">
2
+ <div class="label ${o?"global":""}">${r(c)}</div>
3
+ <div class="preview">${d}</div>
4
+ <div class="meta"><span>${m}</span></div>
5
5
  </a>`}).join(`
6
- `),c=n.length?l:'<p class="empty">No notes yet.</p>',p=`
6
+ `),l=n.length?s:'<p class="empty">No notes yet.</p>',i=`
7
7
  .note-card {
8
8
  display: block; padding: 16px 18px; border: 1px solid var(--panel-border); border-radius: 12px;
9
9
  margin-bottom: 10px; text-decoration: none; color: var(--page-fg);
@@ -26,8 +26,8 @@ import{cssVarsStyle as b}from"../theme.js";import{commandbarCSS as x,commandbarH
26
26
  display: flex; justify-content: space-between;
27
27
  }
28
28
  .empty { font-size: var(--text-sm); color: var(--panel-muted); line-height: 1.6; margin-top: 20px; }
29
- ${r?x():""}
30
- ${u()}`;return`<!DOCTYPE html>
29
+
30
+ ${v()}`;return`<!DOCTYPE html>
31
31
  <html lang="en">
32
32
  <head>
33
33
  <meta charset="UTF-8" />
@@ -35,31 +35,29 @@ import{cssVarsStyle as b}from"../theme.js";import{commandbarCSS as x,commandbarH
35
35
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
36
36
  <title>Notes - tmux-web</title>
37
37
  <style>
38
- ${b(o.shell)}
39
- ${$(p)}
38
+ ${b(a.shell)}
39
+ ${h(i)}
40
40
  </style>
41
41
  </head>
42
42
  <body>
43
43
 
44
- ${y({commandbarEnabled:r,title:"All Notes",themeTemplate:o.template})}
44
+ ${f({title:"All Notes",themeTemplate:a.template})}
45
45
 
46
46
  <div class="page-wrap">
47
47
  <div class="page-layout">
48
- ${_({activePage:"notes",refreshHref:"/notes"})}
48
+ ${u({activePage:"notes",refreshHref:"/notes"})}
49
49
  <main class="main-panel">
50
- <div id="notes-list">${c}</div>
50
+ <div id="notes-list">${l}</div>
51
51
  </main>
52
52
  </div>
53
53
  </div>
54
54
 
55
- ${k()}
56
- ${r?f():""}
57
- ${w("Notes - Global")}
55
+ ${w()}
56
+ ${g("Notes - Global")}
58
57
 
59
58
  <script type="module">
60
- ${S("__global__")}
61
- ${r?h(i,[]):""}
62
- ${D()}
59
+ ${x("__global__")}
60
+ ${y()}
63
61
  </script>
64
62
  </body>
65
- </html>`}export{M as renderNotesIndex};
63
+ </html>`}export{D as renderNotesIndex};
@@ -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,12 +1,12 @@
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 m}from"../theme.js";import{getThemeTemplates as g,THEME_TEMPLATE_IDS as v}from"../themes/index.js";function s(a){return a.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function p(a,e){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>${n(a)} - tmux-web</title>
7
+ <title>${s(a)} - tmux-web</title>
8
8
  <style>
9
- ${h(e.shell)}
9
+ ${m(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; }
@@ -47,16 +47,6 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
47
47
  .btn:hover { border-color: var(--panel-accent); color: var(--panel-accent); }
48
48
  .btn.primary { border-color: var(--panel-success); color: var(--panel-success); }
49
49
  .btn.danger:hover { border-color: #e06c75; color: #e06c75; }
50
- .plugin-row { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 8px 0; font-size: var(--text-sm); border-top: 1px solid var(--panel-border); }
51
- .plugin-row:first-of-type { border-top: none; }
52
- .plugin-row .pkg { word-break: break-all; }
53
- .plugin-add { display: flex; gap: 10px; margin-top: 14px; }
54
- .plugin-add input[type=text] {
55
- flex: 1; font-size: var(--text-sm); font-family: inherit; color: var(--page-fg);
56
- background: var(--page-bg); border: 1px solid var(--panel-border);
57
- border-radius: 12px; padding: 9px 12px; outline: none; transition: border-color 0.15s, box-shadow 0.15s;
58
- }
59
- .plugin-add input[type=text]:focus { border-color: var(--panel-accent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--panel-accent) 8%, transparent); }
60
50
  .num-input {
61
51
  width: 100px; font-size: var(--text-sm); font-family: inherit; color: var(--page-fg);
62
52
  background: var(--page-bg); border: 1px solid var(--panel-border);
@@ -87,15 +77,7 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
87
77
  .num-input { width: 100%; }
88
78
  }
89
79
  </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">
91
- <span class="pkg">${n(p)}</span>
92
- <form method="POST" action="/settings/plugins" onsubmit="return confirm('Remove ${n(p)}?');">
93
- <input type="hidden" name="action" value="remove" />
94
- <input type="hidden" name="pkg" value="${n(p)}" />
95
- <button type="submit" class="btn danger">Remove</button>
96
- </form>
97
- </div>`).join(`
98
- `):'<p class="desc" style="margin:0">No plugins enabled.</p>';return`${g("Settings",l)}
80
+ </head>`}function h(a,e){let t="";return a&&(t+='<div class="saved-flash">\u2713 Saved. Restart tmux-web to apply.</div>'),e&&(t+=`<div class="error-flash">${s(e)}</div>`),t}function y(a){const{settings:e,renderer:t,rendererOverridden:i,theme:l,saved:r=!1,error:c}=a,n=e.terminalRenderer??"xterm",o=e.defaultView??"default";return`${p("Settings",l)}
99
81
  <body>
100
82
  <div class="container">
101
83
  <div class="page-header">
@@ -108,56 +90,33 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
108
90
  <strong>restart the tmux-web process</strong> after making changes for them to take effect.
109
91
  </div>
110
92
 
111
- ${f(d,s)}
93
+ ${h(r,c)}
112
94
 
113
95
  <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
96
  <div class="section">
121
97
  <h2>Terminal library</h2>
122
98
  <p class="desc">Rendering engine for the terminal view.</p>
123
99
  <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>
100
+ <label class="row"><input type="radio" name="terminalRenderer" value="xterm" ${n==="xterm"?"checked":""} /> xterm.js (default)</label>
101
+ <label class="row"><input type="radio" name="terminalRenderer" value="ghostty" ${n==="ghostty"?"checked":""} /> ghostty-web</label>
126
102
  </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>`:""}
103
+ ${i?`<p class="override-note">\u26A0 A CLI flag or <code>TMUX_WEB_TERMINAL_RENDERER</code> env var is currently forcing <strong>${t}</strong>, overriding this setting for the running process.</p>`:""}
128
104
  </div>
129
105
 
130
106
  <div class="section">
131
107
  <h2>Default home tab</h2>
132
108
  <p class="desc">Which tab the home page opens on.</p>
133
109
  <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>
110
+ <label class="row"><input type="radio" name="defaultView" value="default" ${o==="default"?"checked":""} /> Default</label>
111
+ <label class="row"><input type="radio" name="defaultView" value="recent" ${o==="recent"?"checked":""} /> Last Updated</label>
136
112
  </div>
137
113
  </div>
138
114
 
139
- <div class="section">
140
- <h2>Schedule history</h2>
141
- <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>
143
- </div>
144
-
145
115
  <div class="form-actions">
146
116
  <button type="submit" class="btn primary">Save settings</button>
147
117
  </div>
148
118
  </form>
149
119
 
150
- <div class="section" style="margin-top:16px">
151
- <h2>Plugins</h2>
152
- <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}
154
- <form method="POST" action="/settings/plugins" class="plugin-add">
155
- <input type="hidden" name="action" value="add" />
156
- <input type="text" id="pkg-input" name="pkg" placeholder="npm package name" autocomplete="off" />
157
- <button type="submit" class="btn">Add</button>
158
- </form>
159
- </div>
160
-
161
120
  <div class="section">
162
121
  <h2>Theme</h2>
163
122
  <p class="desc">Shell chrome + terminal colors.</p>
@@ -171,14 +130,14 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
171
130
  </div>
172
131
  </div>
173
132
  </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":""}">
133
+ </html>`}const x={vscode:"VS Code",ghostty:"Ghostty","warm-clay":"Warm Clay","dark-cove":"Dark Cove"},b=["background","foreground","red","green","yellow","blue","magenta","cyan"];function w(a){const{theme:e,saved:t=!1}=a,i=g(),l=v.map(r=>{const c=i[r],n=e.template===r,o=b.map(d=>`<span class="swatch" style="background:${s(c.terminal[d])}" title="${d}"></span>`).join("");return`<label class="theme-card${n?" active":""}">
175
134
  <div class="tname">
176
- <input type="radio" name="template" value="${t}" ${s?"checked":""} style="accent-color:var(--panel-success)" />
177
- ${n(y[t]??t)}
135
+ <input type="radio" name="template" value="${r}" ${n?"checked":""} style="accent-color:var(--panel-success)" />
136
+ ${s(x[r]??r)}
178
137
  </div>
179
- <div class="swatches">${c}</div>
138
+ <div class="swatches">${o}</div>
180
139
  </label>`}).join(`
181
- `);return`${g("Theme",e)}
140
+ `);return`${p("Theme",e)}
182
141
  <body>
183
142
  <div class="container">
184
143
  <div class="page-header">
@@ -190,7 +149,7 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
190
149
  <strong>Note:</strong> the active theme is applied immediately to new page renders.
191
150
  </div>
192
151
 
193
- ${r?'<div class="saved-flash">\u2713 Theme saved.</div>':""}
152
+ ${t?'<div class="saved-flash">\u2713 Theme saved.</div>':""}
194
153
 
195
154
  <form method="POST" action="/settings/theme">
196
155
  <div class="theme-grid">
@@ -202,4 +161,4 @@ import{cssVarsStyle as h}from"../theme.js";import{getThemeTemplates as b,THEME_T
202
161
  </form>
203
162
  </div>
204
163
  </body>
205
- </html>`}export{T as renderSettings,S as renderThemeSettings};
164
+ </html>`}export{y as renderSettings,w 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">
@@ -722,8 +712,8 @@ import{cssVarsStyle as g}from"../theme.js";import{commandbarCSS as b,commandbarH
722
712
  <button class="theme-option" data-theme="dark-cove" title="Dark Cove"><span class="theme-dot" style="background:#7aa2f7"></span>Dark Cove${e.template==="dark-cove"?'<span class="theme-check">\u2713</span>':""}</button>
723
713
  </div>
724
714
  <hr class="settings-divider" />
725
- <a href="/settings" class="settings-item" id="set-plugins-link" style="cursor:pointer;color:inherit;text-decoration:none">
726
- <span>Plugins & Settings</span>
715
+ <a href="/settings" class="settings-item" id="set-settings-link" style="cursor:pointer;color:inherit;text-decoration:none">
716
+ <span>Settings</span>
727
717
  <span style="font-size:var(--text-xs);color:var(--panel-muted)">\u2192</span>
728
718
  </a>
729
719
  </div>
@@ -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};