drixio 1.1.2 → 1.1.3

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,126 +0,0 @@
1
- (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=`<header>\r
2
- <div id="current-path">\r
3
- <span id="db-name">database</span>\r
4
- <span id="slash">/</span>\r
5
- <div id="current-table">\r
6
- <span class="material-symbols-outlined" id="table-icon"> table </span>\r
7
- <span id="table-name">users</span>\r
8
- </div>\r
9
- </div>\r
10
- </header>\r
11
- `,t=`<aside>\r
12
- <div id="sidebar-header">\r
13
- <span class="material-symbols-outlined" id="database-icon"> database </span>\r
14
- <h1 id="brand-title">\r
15
- DRIXIO\r
16
- <p id="brand-subtitle">STUDIO</p>\r
17
- </h1>\r
18
- </div>\r
19
- \r
20
- <div id="sidebar-content">\r
21
- <div id="search-bar">\r
22
- <span class="material-symbols-outlined" id="search-icon"> search </span>\r
23
- <input type="text" placeholder="Search" id="search-input" />\r
24
- </div>\r
25
- \r
26
- <nav id="table-nav">\r
27
- <!-- Display All Table -->\r
28
- </nav>\r
29
- </div>\r
30
- \r
31
- <div id="sidebar-footer">\r
32
- <button id="setting-btn">Settings</button>\r
33
- </div>\r
34
- </aside>\r
35
- `,n=`<nav id="tab-nav">\r
36
- <button\r
37
- type="button"\r
38
- class="tab-btn"\r
39
- onclick="handleSwitchTab('data-btn')"\r
40
- id="data-btn"\r
41
- >\r
42
- <span class="material-symbols-outlined" id="data-icon"> table_rows </span>\r
43
- Data\r
44
- </button>\r
45
- <button\r
46
- class="tab-btn"\r
47
- onclick="handleSwitchTab('schema-btn')"\r
48
- id="schema-btn"\r
49
- >\r
50
- <span class="material-symbols-outlined" id="schema-icon">\r
51
- grid_layout_side\r
52
- </span>\r
53
- Schema (Structure)\r
54
- </button>\r
55
- <button class="tab-btn" onclick="handleSwitchTab('erd-btn')" id="erd-btn">\r
56
- <span class="material-symbols-outlined" id="erd-icon"> schema </span>\r
57
- ERD Visualization\r
58
- </button>\r
59
- <button class="tab-btn" onclick="handleSwitchTab('sql-btn')" id="sql-btn">\r
60
- <span class="material-symbols-outlined" id="sql-icon"> code </span>\r
61
- SQL Console\r
62
- </button>\r
63
- </nav>\r
64
- `;async function r(){return await(await fetch(`/api/tables`)).json()}async function i(){return await(await fetch(`/api/tables/stats`)).json()}async function a(e,t={}){let{where:n=``,limit:r=50,offset:i=0,orderCol:a,orderAsc:o}=t,s=new URLSearchParams;n&&s.append(`where`,n),s.append(`limit`,r.toString()),s.append(`offset`,i.toString()),a&&(s.append(`orderCol`,a),s.append(`orderAsc`,o===!1?`false`:`true`));let c=`/api/tables/${e}/data?${s.toString()}`;return await(await fetch(c)).json()}async function o(e){return await(await fetch(`/api/tables/${e}/schema`)).json()}async function s(e){return await(await fetch(`/api/query`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sql:e})})).json()}async function c(){try{let e=await r(),t=document.getElementById(`table-nav`),n=document.getElementById(`not-found-msg`);n&&n.remove(),e.success&&e.data&&e.data.length>0?(e.data.forEach(e=>{let n=document.createElement(`button`);n.type=`button`,n.className=`table-btn`,n.innerHTML=`<span>${e}</span><span class="table-btn-badge" id="badge-${e}" style="display:none;"></span>`,n.onclick=()=>{window.AppState.currentTable=e,window.AppState.currentTableBtnElement=n,window.renderCurrentView()},t.appendChild(n)}),window.handleSwitchTab(`data-btn`),i().then(e=>{e.success&&e.data&&Object.entries(e.data).forEach(([e,t])=>{let n=document.getElementById(`badge-${e}`);n&&(n.textContent=Number(t).toLocaleString(),n.style.display=`inline-flex`)})}).catch(e=>console.error(`Failed to load table stats:`,e))):(t.innerHTML=`<div id="not-found-msg">No Tables Found.</div>`,window.handleSwitchTab(`data-btn`))}catch(e){console.error(`Failed to fetch tables:`,e)}}async function l(){if(!window.DataGrid)return;let{pendingEdits:e,pendingInserts:t,pkColumn:n}=window.DataGrid,r=window.AppState.currentTable;if(!r||!n){alert(`Cannot save: No Primary Key detected for this table.`);return}let i=[];for(let[t,a]of Object.entries(e)){if(Object.keys(a).length===0)continue;let e=Object.entries(a).map(([e,t])=>t===``?`"${e}" = NULL`:`"${e}" = '${t.replace(/'/g,`''`)}'`).join(`, `);i.push(`UPDATE "${r}" SET ${e} WHERE "${n}" = '${t.replace(/'/g,`''`)}';`)}for(let e=0;e<t.length;e++){let n=t[e];if(Object.keys(n).length===0||!Object.values(n).some(e=>e!==``))continue;let a=Object.keys(n),o=a.map(e=>{let t=n[e];return t===``?`NULL`:`'${t.replace(/'/g,`''`)}'`});i.push(`INSERT INTO "${r}" ("${a.join(`", "`)}") VALUES (${o.join(`, `)});`)}if(window.DataGrid.pendingDeletes)for(let e of window.DataGrid.pendingDeletes)i.push(`DELETE FROM "${r}" WHERE "${n}" = '${e.replace(/'/g,`''`)}';`);if(i.length===0)return;let a=!0,o=``;for(let e of i)try{let t=await s(e);if(!t.success){a=!1,o=t.error;break}}catch(e){a=!1,o=e.message;break}a?window.renderCurrentView():(alert(`Save failed:
65
- `+o),document.querySelectorAll(`.cell-edited`).forEach(e=>{e.classList.remove(`cell-edited`),e.classList.add(`cell-error`)}))}function u(e,t,n,r=!0){if(r&&window.DataGrid.currentTransaction){let n=e.textContent;(n===`null`||e.classList.contains(`ghost-row`))&&(n=``),n!==t&&window.DataGrid.currentTransaction.push({td:e,oldVal:n,newVal:t})}let i=e.dataset.col;if(e.innerHTML=t||(e.dataset.insertIndex===void 0?`<em>null</em>`:`+ New`),e.dataset.insertIndex!==void 0){let r=parseInt(e.dataset.insertIndex);if(window.DataGrid.pendingInserts[r]||(window.DataGrid.pendingInserts[r]={}),t&&(window.DataGrid.pendingInserts[r][i]=t,e.classList.add(`cell-edited`),e.classList.remove(`ghost-row`),r===window.DataGrid.pendingInserts.length-1)){window.DataGrid.pendingInserts.push({});let t=document.querySelector(`#data-grid-table tbody`),i=document.createElement(`tr`);i.className=`ghost-row-tr`;let a=parseInt(e.dataset.rowIdx)+1;i.innerHTML+=`<td class="row-header" data-row-idx="${a}">*</td>`,n.forEach((e,t)=>{i.innerHTML+=`<td class="data-cell ghost-row" data-row-idx="${a}" data-col-idx="${t}" data-insert-index="${r+1}" data-col="${e}">+ New</td>`}),t.appendChild(i)}}else{let n=e.dataset.pk;t===e.dataset.original?(e.classList.remove(`cell-edited`),e.classList.remove(`cell-error`),window.DataGrid.pendingEdits[n]&&delete window.DataGrid.pendingEdits[n][i]):(window.DataGrid.pendingEdits[n]||(window.DataGrid.pendingEdits[n]={}),window.DataGrid.pendingEdits[n][i]=t,e.classList.add(`cell-edited`),e.classList.remove(`cell-error`))}}function d(){document.querySelectorAll(`.cell-in-range, .cell-selected, .range-top, .range-bottom, .range-left, .range-right`).forEach(e=>{e.classList.remove(`cell-in-range`,`cell-selected`,`range-top`,`range-bottom`,`range-left`,`range-right`)});let e=window.DataGrid.selection;if(e.startRow===-1)return;let t=Math.min(e.startRow,e.endRow),n=Math.max(e.startRow,e.endRow),r=Math.min(e.startCol,e.endCol),i=Math.max(e.startCol,e.endCol);document.querySelectorAll(`td.data-cell`).forEach(a=>{let o=parseInt(a.dataset.rowIdx),s=parseInt(a.dataset.colIdx);o>=t&&o<=n&&s>=r&&s<=i&&(a.classList.add(`cell-in-range`),o===t&&a.classList.add(`range-top`),o===n&&a.classList.add(`range-bottom`),s===r&&a.classList.add(`range-left`),s===i&&a.classList.add(`range-right`),o===e.startRow&&s===e.startCol&&(a.classList.add(`cell-selected`),window.DataGrid.selectedCell=a))})}function f(e,t){e.addEventListener(`mousedown`,e=>{if(e.target.tagName===`INPUT`||e.target.tagName===`SELECT`)return;let n=e.target.closest(`td.row-header`);if(n){let e=parseInt(n.dataset.rowIdx);window.DataGrid.selection={isDragging:!1,startRow:e,endRow:e,startCol:0,endCol:t-1},d();return}let r=e.target.closest(`td.data-cell`);if(!r)return;let i=parseInt(r.dataset.rowIdx),a=parseInt(r.dataset.colIdx);window.DataGrid.selection={isDragging:!0,startRow:i,startCol:a,endRow:i,endCol:a},d()}),e.addEventListener(`mouseover`,e=>{if(!window.DataGrid.selection.isDragging)return;let t=e.target.closest(`td.data-cell`);t&&(window.DataGrid.selection.endRow=parseInt(t.dataset.rowIdx),window.DataGrid.selection.endCol=parseInt(t.dataset.colIdx),d())})}function p(e){let t=document.createElement(`div`);t.className=`resizer`,e.appendChild(t),t.addEventListener(`click`,e=>e.stopPropagation()),t.addEventListener(`mousedown`,t=>{t.preventDefault(),t.stopPropagation();let n=t.pageX,r=e.offsetWidth,i=!1,a=t=>{i=!0,window.DataGrid&&(window.DataGrid.isResizing=!0);let a=r+(t.pageX-n);e.style.width=a+`px`,e.style.minWidth=a+`px`,e.style.maxWidth=a+`px`},o=()=>{document.removeEventListener(`mousemove`,a),document.removeEventListener(`mouseup`,o),document.body.style.cursor=``,i&&setTimeout(()=>{window.DataGrid&&(window.DataGrid.isResizing=!1)},100)};document.body.style.cursor=`col-resize`,document.addEventListener(`mousemove`,a),document.addEventListener(`mouseup`,o)})}function m(e,t,n){e.addEventListener(`dblclick`,e=>{let r=e.target.closest(`td.data-cell`);if(!r||r.querySelector(`input, select`))return;let i=r.dataset.col,a=t.find(e=>e.name===i),o=a?.type?.toUpperCase()||``,s=o.includes(`ENUM`),c=o===`DATE`,l=o.includes(`DATETIME`)||o.includes(`TIMESTAMP`),d=o.includes(`BOOL`)||o===`TINYINT(1)`,f=r.textContent===`null`||r.textContent===`+ New`?``:r.textContent,p;if(s){let e=a.type.match(/enum\((.*?)\)/i),t=[];e&&(t=e[1].split(`,`).map(e=>e.trim().replace(/^'|'$/g,``))),p=document.createElement(`select`),t.forEach(e=>{let t=document.createElement(`option`);t.value=e,t.textContent=e,e===f&&(t.selected=!0),p.appendChild(t)})}else if(c)p=document.createElement(`input`),p.type=`date`,p.value=f;else if(l){p=document.createElement(`input`),p.type=`datetime-local`;let e=f.replace(` `,`T`).slice(0,16);p.value=e}else d?(p=document.createElement(`input`),p.type=`checkbox`,p.checked=f===`1`||f.toLowerCase()===`true`):(p=document.createElement(`input`),p.type=`text`,p.value=f);let m=!1,h=()=>{m=!0;let e=document.getElementById(`modal-editor-overlay`),t=document.getElementById(`modal-textarea`),n=document.getElementById(`modal-cancel-btn`),r=document.getElementById(`modal-save-btn`),a=document.getElementById(`modal-title`);a.textContent=`Edit ${i}`,t.value=p.value,e.style.display=`flex`,t.focus();let o=()=>{e.style.display=`none`,r.onclick=null,n.onclick=null,m=!1,p.focus()};n.onclick=o,r.onclick=()=>{p.value=t.value,o(),g()}};if(r.innerHTML=``,r.appendChild(p),o===``||!s&&!c&&!l&&!d){let e=document.createElement(`span`);e.className=`material-symbols-outlined cell-expand-btn`,e.textContent=`open_in_full`,e.onmousedown=e=>e.preventDefault(),e.onclick=()=>h(),r.appendChild(e),p.style.width=`100%`,p.style.paddingRight=`32px`,p.addEventListener(`keydown`,e=>{e.key===`Enter`&&e.shiftKey?(e.preventDefault(),h()):e.key===`Enter`&&p.blur()})}else p.addEventListener(`keydown`,e=>{e.key===`Enter`&&p.blur()});p.focus();let g=()=>{if(m)return;let e=d?p.checked?`1`:`0`:p.value;l&&e&&(e=e.replace(`T`,` `)+`:00`),window.DataGrid.currentTransaction=[],u(r,e,n),window.DataGrid.currentTransaction.length>0&&window.DataGrid.history.push(window.DataGrid.currentTransaction),window.DataGrid.currentTransaction=null};p.addEventListener(`blur`,()=>{setTimeout(()=>{m||g()},100)})})}function h(){let e=document.getElementById(`filter-val`)?.value.trim(),t=document.getElementById(`filter-op`)?.value,n=document.getElementById(`filter-col`)?.value,r=``;if(e||t===`IS NULL`){let i=e;i&&!i.startsWith(`'`)&&!i.endsWith(`'`)&&isNaN(Number(i))&&(i=`'${i.replace(/'/g,`''`)}'`),r=`"${n}" ${t} ${i}`}return r}function g(e,t,n,r){let i=`<td class="row-header" data-row-idx="${t}">${t+1}</td>`,a=n?e[n]:t;return r.forEach((n,r)=>{let o=e[n]===null?`null`:String(e[n]),s=o.replace(/"/g,`&quot;`),c=o===`null`?`<em>null</em>`:o.replace(/</g,`&lt;`);i+=`<td class="data-cell" data-row-idx="${t}" data-col-idx="${r}" data-pk="${a}" data-col="${n}" data-original="${s}">${c}</td>`}),i}async function _(e,t,n=``,r=!1){document.querySelectorAll(`.table-btn`).forEach(e=>e.classList.remove(`active`)),t&&t.classList.add(`active`);let i=document.getElementById(`table-name`);i&&(i.textContent=e);let s=document.getElementById(`main-content`);s.innerHTML=`<div style='padding:24px;'>Loading...</div>`;try{let i=await o(e);if(!i.success)throw Error(i.error);let c=i.data,l=c.find(e=>e.isPk)?.name;(!r||!window.DataGrid)&&(window.DataGrid={schema:c,pkColumn:l,pendingEdits:{},pendingInserts:[{}],pendingDeletes:new Set,selectedCell:null,history:[],currentTransaction:null,sortState:{col:l||c[0].name,asc:!0},pagination:{limit:50,offset:0,isLoading:!1,hasMore:!0},selection:{isDragging:!1,startRow:-1,startCol:-1,endRow:-1,endCol:-1}});let u=await a(e,{where:n,limit:window.DataGrid.pagination.limit,offset:window.DataGrid.pagination.offset,orderCol:window.DataGrid.sortState.col,orderAsc:window.DataGrid.sortState.asc});if(u.success&&u.data){let r=u.data.rows,i=u.data.columns;window.DataGrid.pagination.hasMore=r.length===window.DataGrid.pagination.limit;let a=`
66
- <div class="toolbar">
67
- <div class="filter-group">
68
- <div class="filter-icon-container">
69
- <span class="material-symbols-outlined" id="filter-icon">filter_list</span>
70
- <span>Filter</span>
71
- </div>
72
- <select id="filter-col" class="filter-select">${i.map(e=>`<option value="${e}">${e}</option>`).join(``)}</select>
73
- <select id="filter-op" class="filter-select">
74
- <option value="=">=</option>
75
- <option value=">">></option>
76
- <option value="<"><</option>
77
- <option value=">=">>=</option>
78
- <option value="<="><=</option>
79
- <option value="LIKE">LIKE</option>
80
- <option value="!=">!=</option>
81
- </select>
82
- <input type="text" id="filter-val" class="filter-input" placeholder="Enter value..." />
83
- </div>
84
- <button id="btn-run-query"><span class="material-symbols-outlined">check</span> Apply</button>
85
- ${n?`<button id="btn-clear-query"><span class="material-symbols-outlined">close</span> Clear</button>`:``}
86
- <button id="btn-refresh-data" title="Refresh Data (F5)"><span class="material-symbols-outlined">refresh</span></button>
87
- </div>
88
- `;a+=`<div class="table-container" id="data-grid-container"><table class="data-table" id="data-grid-table"><thead><tr>`,a+=`<th class="row-header">#</th>`,i.forEach(e=>{let t=c.find(t=>t.name===e),n=``,r=``;t&&(t.isPk&&(n=` <span style="opacity:0.5; font-size:10px;">(PK)</span>`),t.name.toLowerCase().includes(`id`)&&!t.isPk&&(n=` <span style="opacity:0.5; font-size:10px;">(FK)</span>`),r=`<br><span style="font-weight:normal; opacity:0.7; font-size:10px; font-family:monospace;">${t.type}</span>`);let i=``;window.DataGrid.sortState.col===e&&(i=window.DataGrid.sortState.asc?`▲`:`▼`),a+=`<th class="sortable" data-col="${e}" style="cursor:pointer; user-select:none;">
89
- <div style="display: flex; justify-content: space-between; align-items: center;">
90
- <div>${e}${n}${r}</div>
91
- <div class="sort-arrow" style="font-size:10px; opacity:0.8; margin-left: 8px; width: 12px; text-align: right;">${i}</div>
92
- </div>
93
- </th>`}),a+=`</tr></thead><tbody>`,r&&r.length>0&&r.forEach((e,t)=>{a+=`<tr>${g(e,t,l,i)}</tr>`}),a+=`<tr class="ghost-row-tr">`;let o=r?r.length:0;a+=`<td class="row-header" data-row-idx="${o}">*</td>`,i.forEach((e,t)=>{a+=`<td class="data-cell ghost-row" data-row-idx="${o}" data-col-idx="${t}" data-insert-index="0" data-col="${e}">+ New</td>`}),a+=`</tr></tbody></table></div>`,s.innerHTML=a;let d=document.getElementById(`data-grid-container`);document.querySelectorAll(`th.sortable`).forEach(n=>{n.onclick=r=>{if(window.DataGrid&&window.DataGrid.isResizing)return;if(Object.keys(window.DataGrid.pendingEdits).length>0||window.DataGrid.pendingInserts.length>1||window.DataGrid.pendingDeletes.size>0){alert(`你有未儲存的變更!因為分頁與排序需要向資料庫重新載入資料,請先按下 Ctrl+S 儲存變更,然後再點擊排序。`);return}let i=n.dataset.col;window.DataGrid.sortState.col===i?window.DataGrid.sortState.asc=!window.DataGrid.sortState.asc:(window.DataGrid.sortState.col=i,window.DataGrid.sortState.asc=!0),window.DataGrid.pagination.offset=0,_(e,t,h(),!0)},p(n)}),f(d,i.length),m(d,c,i);let v=document.getElementById(`btn-run-query`),y=document.getElementById(`btn-clear-query`),b=document.getElementById(`filter-val`),x=(n=!0)=>{n&&window.DataGrid&&(window.DataGrid.pagination.offset=0);let r=b?.value.trim(),i=document.getElementById(`filter-op`)?.value;!r&&i!==`IS NULL`||_(e,t,h(),!0)};v&&(v.onclick=()=>x(!0)),b&&b.addEventListener(`keydown`,e=>{e.key===`Enter`&&x(!0)}),y&&(y.onclick=()=>_(e,t,``,!0));let S=()=>{(Object.keys(window.DataGrid.pendingEdits).length>0||window.DataGrid.pendingInserts.length>1||window.DataGrid.pendingDeletes.size>0)&&!confirm(`你有未儲存的變更!如果重新整理,這些變更將會遺失。確定要捨棄變更並重新整理嗎?`)||x(!1)},C=document.getElementById(`btn-refresh-data`);C&&(C.onclick=S),window.DataGrid.refreshData=S}else s.innerHTML=`<div style="padding:24px; color:red;">Error: ${u.error}</div>`}catch(e){s.innerHTML=`<div style="padding:24px; color:red;">Failed to load data: ${e.message}</div>`}}async function v(e,t){document.querySelectorAll(`.table-btn`).forEach(e=>e.classList.remove(`active`)),t&&t.classList.add(`active`);let n=document.getElementById(`table-name`);n&&(n.textContent=e+` (Schema)`);let r=document.getElementById(`main-content`);r.innerHTML=`<div style='padding:24px;'>Loading Schema...</div>`;try{let t=await o(e);if(t.success&&t.data){let e=t.data;if(e.length===0){r.innerHTML=`<div style='padding:24px;'>No schema found.</div>`;return}let n=`<div class="table-container"><table class="data-table"><thead><tr>`;[`Name`,`Type`,`Nullable`,`Primary Key`].forEach(e=>n+=`<th>${e}</th>`),n+=`</tr></thead><tbody>`,e.forEach(e=>{n+=`<tr>
94
- <td><strong>${e.name}</strong></td>
95
- <td><code>${e.type}</code></td>
96
- <td>${e.nullable?`Yes`:`No`}</td>
97
- <td>${e.isPk?`Yes`:`No`}</td>
98
- </tr>`}),n+=`</tbody></table></div>`,r.innerHTML=n}else r.innerHTML=`<div style="padding:24px; color:red;">Error: ${t.error}</div>`}catch(e){r.innerHTML=`<div style="padding:24px; color:red;">Failed to load schema: ${e.message}</div>`}}function y(e,t){document.querySelectorAll(`.table-btn`).forEach(e=>e.classList.remove(`active`)),t&&t.classList.add(`active`);let n=document.getElementById(`table-name`);n&&(n.textContent=`SQL Console`);let r=document.getElementById(`main-content`);r.innerHTML=`
99
- <div id="console-container" style="display: flex; flex-direction: column; flex: 1; height: 100%; min-width: 0;">
100
- <div id="console-editor-pane" style="flex: 1; display: flex; flex-direction: column; border-bottom: 1px solid var(--color-border); position: relative; min-height: 200px;">
101
- <div id="sql-editor" style="flex: 1; font-size: 14px;"></div>
102
- <button id="run-sql-btn" class="primary" style="position: absolute; bottom: 16px; right: 24px; padding: 8px 16px; border-radius: 6px; border: none; background-color: var(--color-primary); color: #fff; font-weight: 600; cursor: pointer; box-shadow: 0 4px 6px rgba(0,0,0,0.1); z-index: 50; display: flex; align-items: center; gap: 6px; transition: all 0.2s;">
103
- <span class="material-symbols-outlined" style="font-size: 18px;">play_arrow</span> Run (Ctrl+Enter)
104
- </button>
105
- </div>
106
- <div id="console-results-pane" style="flex: 1; display: flex; flex-direction: column; overflow: hidden; background: #fff; min-height: 200px;">
107
- <div id="console-results-header" style="padding: 8px 16px; background-color: var(--color-bg-secondary); border-bottom: 1px solid var(--color-border); font-size: 12px; color: var(--color-text-soft); font-weight: 600;">RESULTS</div>
108
- <div class="table-container" id="console-table-container" style="flex: 1;">
109
- <div style="padding: 24px; color: var(--color-text-soft); text-align: center; font-size: 14px;">Run a query to see results.</div>
110
- </div>
111
- </div>
112
- </div>
113
- `;let i=window.ace.edit(`sql-editor`);i.setTheme(`ace/theme/chrome`),i.session.setMode(`ace/mode/sql`),i.setOptions({showPrintMargin:!1,fontSize:`14px`,fontFamily:`ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace`,highlightActiveLine:!0}),window.AppState.lastQuery?i.setValue(window.AppState.lastQuery,1):i.setValue(`-- Enter your SQL query here
114
- SELECT * FROM sqlite_master;
115
- `,1),i.focus();let a=async()=>{let e=i.getValue().trim();if(!e)return;window.AppState.lastQuery=e;let t=document.getElementById(`console-table-container`),n=document.getElementById(`console-results-header`);n.textContent=`EXECUTING...`,n.style.color=`var(--color-primary)`,t.innerHTML=`<div style="padding: 24px; text-align: center; color: var(--color-text-soft);">Executing query...</div>`;try{let r=await s(e);if(!r.success){n.textContent=`ERROR`,n.style.color=`red`,t.innerHTML=`<div style="padding: 24px; color: red; font-family: monospace; white-space: pre-wrap;">${r.error}</div>`;return}let i=r.data.rows||[];if(n.textContent=`SUCCESS - ${i.length} rows returned`,n.style.color=`green`,i.length===0){t.innerHTML=`<div style="padding: 24px; text-align: center; color: var(--color-text-soft);">0 rows returned.</div>`;return}let a=Object.keys(i[0]),o=document.createElement(`table`);o.className=`data-table`;let c=document.createElement(`thead`),l=document.createElement(`tr`),u=document.createElement(`th`);u.className=`row-header`,u.textContent=`#`,l.appendChild(u),a.forEach(e=>{let t=document.createElement(`th`);t.textContent=e;let n=document.createElement(`div`);n.className=`resizer`,t.appendChild(n),n.addEventListener(`click`,e=>e.stopPropagation()),n.addEventListener(`mousedown`,e=>{e.preventDefault(),e.stopPropagation();let n=e.pageX,r=t.offsetWidth,i=e=>{let i=r+(e.pageX-n);t.style.width=i+`px`,t.style.minWidth=i+`px`,t.style.maxWidth=i+`px`},a=()=>{document.removeEventListener(`mousemove`,i),document.removeEventListener(`mouseup`,a),document.body.style.cursor=``};document.body.style.cursor=`col-resize`,document.addEventListener(`mousemove`,i),document.addEventListener(`mouseup`,a)}),l.appendChild(t)}),c.appendChild(l),o.appendChild(c);let d=document.createElement(`tbody`);i.forEach((e,t)=>{let n=document.createElement(`tr`),r=document.createElement(`td`);r.className=`row-header`,r.textContent=t+1,n.appendChild(r),a.forEach(t=>{let r=document.createElement(`td`),i=e[t];if(i===null){let e=document.createElement(`span`);e.textContent=`NULL`,e.style.color=`var(--color-text-soft)`,e.style.fontStyle=`italic`,r.appendChild(e)}else r.textContent=String(i);n.appendChild(r)}),d.appendChild(n)}),o.appendChild(d),t.innerHTML=``,t.appendChild(o)}catch(e){n.textContent=`ERROR`,n.style.color=`red`,t.innerHTML=`<div style="padding: 24px; color: red; font-family: monospace; white-space: pre-wrap;">${e.message}</div>`}};document.getElementById(`run-sql-btn`).onclick=a,i.commands.addCommand({name:`run`,bindKey:{win:`Ctrl-Enter`,mac:`Command-Enter`},exec:function(){a()}})}var b=document.getElementById(`header-container`),x=document.getElementById(`sidebar-container`),S=document.getElementById(`tab-container`);b.innerHTML=e,x.innerHTML=t,S.innerHTML=n,window.AppState={currentTable:null,currentTab:`data-btn`,currentTableBtnElement:null},window.handleSwitchTab=function(e){document.querySelectorAll(`.tab-btn`).forEach(e=>e.classList.remove(`isCurrentTab`));let t=document.getElementById(e);t&&t.classList.add(`isCurrentTab`),window.AppState.currentTab=e,window.renderCurrentView()},window.renderEmptyState=function(){let e=document.getElementById(`main-content`);e.innerHTML=`
116
- <div class="empty-state">
117
- <span class="material-symbols-outlined">database</span>
118
- <h2>No Table Selected</h2>
119
- <p>Select a table from the sidebar to view its data, schema, or run SQL queries.</p>
120
- </div>
121
- `},window.renderCurrentView=function(e=``,t=!1){if(!window.AppState.currentTable){window.renderEmptyState();return}if(window.AppState.currentTab===`data-btn`)_(window.AppState.currentTable,window.AppState.currentTableBtnElement,e,t);else if(window.AppState.currentTab===`schema-btn`)v(window.AppState.currentTable,window.AppState.currentTableBtnElement);else if(window.AppState.currentTab===`console-btn`)y(window.AppState.currentTable,window.AppState.currentTableBtnElement);else if(window.AppState.currentTab===`erd-btn`){let e=document.getElementById(`main-content`);e.innerHTML=`<div style='padding:24px; color: var(--color-text-soft);'>ERD Visualization coming soon!</div>`}},window.saveDataGridEdits=l,document.addEventListener(`DOMContentLoaded`,()=>{c(),document.addEventListener(`mouseup`,()=>{window.DataGrid&&window.DataGrid.selection&&(window.DataGrid.selection.isDragging=!1)}),document.addEventListener(`contextmenu`,e=>{if(window.AppState?.currentTab!==`data-btn`||!window.DataGrid)return;let t=e.target.closest(`td.row-header`);if(!t)return;e.preventDefault();let n=parseInt(t.dataset.rowIdx);document.getElementById(`custom-context-menu`)?.remove();let r=document.createElement(`div`);r.id=`custom-context-menu`,r.className=`context-menu`,r.style.top=`${e.clientY}px`,r.style.left=`${e.clientX}px`,r.innerHTML=`
122
- <div class="context-menu-item danger" id="cmenu-delete">
123
- <span class="material-symbols-outlined" style="font-size:16px;">delete</span> Delete Row
124
- </div>
125
- `,document.body.appendChild(r),document.getElementById(`cmenu-delete`).onclick=()=>{window.DataGrid.currentTransaction=[],window.DataGrid.markRowDeleted(n),window.DataGrid.currentTransaction.length>0&&window.DataGrid.history.push(window.DataGrid.currentTransaction),window.DataGrid.currentTransaction=null,r.remove()};let i=e=>{r.contains(e.target)||(r.remove(),document.removeEventListener(`click`,i))};setTimeout(()=>document.addEventListener(`click`,i),0)}),document.addEventListener(`keydown`,e=>{if(e.key===`F5`){window.AppState?.currentTab===`data-btn`&&window.DataGrid?.refreshData&&(e.preventDefault(),window.DataGrid.refreshData());return}if(!(window.AppState?.currentTab!==`data-btn`||!window.DataGrid)&&!(e.target.tagName===`INPUT`||e.target.tagName===`SELECT`||e.target.tagName===`TEXTAREA`)){if((e.key===`Delete`||e.key===`Backspace`)&&(window.DataGrid.currentTransaction=[],document.querySelectorAll(`.cell-in-range`).forEach(e=>{window.DataGrid.updateCell(e,``)}),window.DataGrid.currentTransaction.length>0&&window.DataGrid.history.push(window.DataGrid.currentTransaction),window.DataGrid.currentTransaction=null),e.key.toLowerCase()===`s`&&(e.ctrlKey||e.metaKey)&&(e.preventDefault(),window.saveDataGridEdits()),e.key.toLowerCase()===`c`&&(e.ctrlKey||e.metaKey)){let e=window.DataGrid.selection;if(e.startRow===-1)return;let t=Math.min(e.startRow,e.endRow),n=Math.max(e.startRow,e.endRow),r=Math.min(e.startCol,e.endCol),i=Math.max(e.startCol,e.endCol),a=``;for(let e=t;e<=n;e++){let t=[];for(let n=r;n<=i;n++){let r=document.querySelector(`td.data-cell[data-row-idx="${e}"][data-col-idx="${n}"]`);if(r){let e=r.textContent.replace(/^null$|^\+ New$/,``);t.push(e)}}a+=t.join(` `)+`
126
- `}navigator.clipboard.writeText(a.trimEnd()),document.querySelectorAll(`.cell-in-range`).forEach(e=>{e.style.backgroundColor=`#bfdbfe`,setTimeout(()=>e.style.backgroundColor=``,150)})}if(e.key===`-`&&(e.ctrlKey||e.metaKey)){e.preventDefault();let t=window.DataGrid.selection;if(t.startRow===-1)return;let n=Math.min(t.startRow,t.endRow),r=Math.max(t.startRow,t.endRow);window.DataGrid.currentTransaction=[];for(let e=n;e<=r;e++)window.DataGrid.markRowDeleted(e);window.DataGrid.currentTransaction.length>0&&window.DataGrid.history.push(window.DataGrid.currentTransaction),window.DataGrid.currentTransaction=null}if(e.key.toLowerCase()===`z`&&(e.ctrlKey||e.metaKey)){e.preventDefault();let t=window.DataGrid.history?.pop();if(t)for(let e=t.length-1;e>=0;e--){let n=t[e];n.type===`delete`?window.DataGrid.unmarkRowDeleted(n.rowIdx,n.pk):window.DataGrid.updateCell(n.td,n.oldVal,!1)}}}}),document.addEventListener(`paste`,e=>{if(window.AppState?.currentTab!==`data-btn`||!window.DataGrid||e.target.tagName===`INPUT`||e.target.tagName===`SELECT`||e.target.tagName===`TEXTAREA`)return;let t=window.DataGrid.selection;if(t.startRow===-1)return;let n=e.clipboardData.getData(`text`);if(!n)return;e.preventDefault();let r=n.split(/\r?\n/).map(e=>e.split(` `)),i=Math.min(t.startRow,t.endRow),a=Math.min(t.startCol,t.endCol);window.DataGrid.currentTransaction=[],r.forEach(e=>{e.forEach((e,t)=>{let n=a+t,r=document.querySelector(`td.data-cell[data-row-idx="${i}"][data-col-idx="${n}"]`);r&&window.DataGrid.updateCell(r,e)}),i++}),window.DataGrid.currentTransaction.length>0&&window.DataGrid.history.push(window.DataGrid.currentTransaction),window.DataGrid.currentTransaction=null})});
@@ -1 +0,0 @@
1
- @import "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap";:root{--color-bg-primary:#fff;--color-bg-secondary:#f8fafc;--color-bg-secondary-dark:#f1f5f9;--color-primary:#2c68ec;--color-primary-active:#eff6ff;--color-primary-dark:#285bb8;--color-text:#0f172a;--color-text-soft:#94a3b8;--color-text-secondary:#64748b;--color-border:#e2e8f0;--color-border-soft:#f1f5f9;--ring-primary-2:0 0 0 2px #2c68ec33;--font-inter:"Inter", sans-serif}body,html{background-color:var(--color-bg-primary);width:100vw;height:100vh;color:var(--color-text);font-family:var(--font-inter);margin:0;padding:0;display:flex;overflow:hidden}main{flex-direction:column;flex:1;min-width:0;display:flex}aside{border-right:1px var(--color-border) solid;flex-direction:column;width:256px;height:100vh;display:flex}#sidebar-header{border-bottom:1px var(--color-border-soft) solid;align-items:center;gap:8px;height:64px;padding:0 16px;display:flex}#database-icon{color:var(--color-primary);font-size:26px}#brand-title{letter-spacing:.5px;align-items:center;gap:4px;margin:0;padding:0;font-size:16px;font-weight:bolder;line-height:1;display:flex}#brand-subtitle{background-color:var(--color-primary);color:#fff;border-radius:5px;align-items:center;padding:3px 5px;font-size:10px;font-weight:600;line-height:1;display:flex}#sidebar-content{flex-direction:column;flex:1;gap:24px;padding:16px;display:flex}#search-bar{background-color:var(--color-bg-secondary);border:1px var(--color-border) solid;border-radius:8px;outline:none;align-items:center;padding:0 4px;transition:all .1s linear;display:flex;overflow:hidden}#search-bar:focus-within{border:1px var(--color-primary) solid;box-shadow:var(--ring-primary-2);background-color:#fff;transform:scale(1.02)}#search-icon{color:var(--color-text-soft);margin:0 3px 0 6px;font-size:20px;transition:all .1s linear}#search-bar:focus-within #search-icon{color:var(--color-primary);transform:scale(1.15)}#search-input{background-color:#0000;border:none;outline:none;width:100%;height:34px;font-size:12px}#search-input::placeholder{color:var(--color-text-soft)}#table-nav{flex-direction:column;flex:1;gap:6px;display:flex;overflow-y:auto}#table-nav::-webkit-scrollbar{width:4px}#table-nav::-webkit-scrollbar-track{background:0 0}#table-nav::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:4px}#table-nav::-webkit-scrollbar-thumb:hover{background:var(--color-text-soft)}.table-btn{color:var(--color-text-secondary);cursor:pointer;background-color:#0000;border:1px solid #0000;border-radius:8px;outline:none;justify-content:space-between;align-items:center;padding:10px 16px;font-size:12px;font-weight:500;transition:all .2s;display:flex}.table-btn:hover{background-color:var(--color-bg-secondary);color:var(--color-text)}.table-btn.active{background-color:var(--color-primary-active);border:1px var(--color-primary) solid;color:var(--color-primary);font-weight:600}.table-btn-badge{background-color:var(--color-bg-secondary-dark);color:var(--color-text-secondary);border-radius:10px;place-content:center;min-width:16px;min-height:16px;font-size:8px;font-weight:600;line-height:1;display:flex}.table-btn.active .table-btn-badge{background-color:var(--color-primary);color:#fff}#not-found-msg{color:var(--color-text-soft);flex:1;justify-content:center;align-items:center;font-size:12px;font-weight:400;display:flex}#sidebar-footer{border-top:1px var(--color-border-soft) solid;justify-content:center;align-items:center;padding:16px;display:flex}#setting-btn{background-color:var(--color-bg-secondary);color:var(--color-text-secondary);border:1px var(--color-border) solid;cursor:pointer;border-radius:8px;width:100%;padding:12px 24px;font-weight:600;transition:all .1s linear}#setting-btn:hover{color:var(--color-primary);border:1px var(--color-primary) solid;background-color:var(--color-bg-primary)}header{border-bottom:1px var(--color-border) solid;justify-content:space-between;align-items:center;width:100%;height:64px;padding:0 32px;font-size:14px;font-weight:300;display:flex;position:sticky;top:0}#current-path{text-transform:lowercase;align-items:center;gap:10px;display:flex}#db-name{color:var(--color-text-secondary)}#slash{color:var(--color-text-soft);font-size:18px;font-weight:lighter}#current-table{align-items:center;gap:4px;display:flex}#table-icon{color:var(--color-primary);font-size:20px}#table-name{color:var(--color-text);font-weight:600}#tab-nav{border-bottom:1px var(--color-border) solid;gap:24px;height:48px;padding:0 32px;display:flex}.tab-btn{height:100%;color:var(--color-text-secondary);cursor:pointer;background-color:#0000;border:none;border-bottom:2px solid #0000;outline:none;align-items:center;gap:8px;padding:0 6px;font-size:12px;font-weight:300;line-height:1;transition:all .1s linear;display:flex}.tab-btn:hover{border-bottom:2px var(--color-border) solid;color:var(--color-text)}.tab-btn.isCurrentTab{border-bottom:2px var(--color-primary) solid;color:var(--color-primary)}.tab-btn .material-symbols-outlined{font-size:16px}#main-content{background-color:var(--color-bg-primary);flex-direction:column;flex:1;min-width:0;display:flex;overflow:hidden}.toolbar{border-bottom:1px var(--color-border) solid;background-color:var(--color-bg-secondary);flex-shrink:0;align-items:center;height:48px;display:flex}.filter-group{flex:1;align-items:center;height:100%;transition:all .15s;display:flex;overflow:hidden}.filter-icon-container{background-color:var(--color-bg-secondary);border-right:1px var(--color-border) solid;align-items:center;gap:6px;height:100%;padding:0 16px;font-size:16px;display:flex}.filter-icon-container .material-symbols-outlined{color:var(--color-text-secondary);font-size:18px}.filter-icon-container span:not(.material-symbols-outlined){text-transform:uppercase;color:var(--color-text-secondary);font-size:13px;font-weight:500}.filter-select{height:100%;color:var(--color-text-secondary);border:none;border-right:1px var(--color-border) solid;cursor:pointer;background-color:#0000;outline:none;padding:0 16px;font-size:13px;font-weight:500}.filter-select:hover{background-color:var(--color-bg-secondary)}.filter-input{background:0 0;border:none;outline:none;flex:1;height:100%;padding:0 20px;font-size:13px;font-weight:200}.filter-input::placeholder{color:var(--color-text-soft)}#btn-run-query{background-color:var(--color-primary);color:var(--color-bg-primary);border:none;border-right:1px var(--color-border) solid;cursor:pointer;border-radius:8px;outline:none;justify-content:center;align-items:center;gap:8px;padding:8px 12px;font-size:10px;font-weight:700;transition:all .1s linear;display:flex}#btn-run-query:hover{background-color:var(--color-primary-dark)}#btn-run-query .material-symbols-outlined{margin-bottom:.5px;font-size:16px}#btn-clear-query{background-color:var(--color-bg-primary);color:var(--color-text-secondary);border:none;border:1px var(--color-border) solid;cursor:pointer;border-radius:8px;outline:none;justify-content:center;align-items:center;gap:8px;margin-left:16px;padding:8px 12px;font-size:10px;font-weight:700;transition:all .1s linear;display:flex}#btn-clear-query:hover{background-color:var(--color-bg-secondary-dark);color:var(--color-text)}#btn-run-query:active,#btn-clear-query:active,.btn-primary:active,.btn-secondary:active,.table-btn:active{transform:scale(.96)}#btn-clear-query .material-symbols-outlined{margin-bottom:.5px;font-size:16px}#btn-refresh-data{background-color:var(--color-bg-secondary);border:1px var(--color-border) solid;color:var(--color-text-secondary);cursor:pointer;border-radius:8px;outline:none;justify-content:center;align-items:center;gap:8px;margin:16px;padding:6px;font-size:10px;font-weight:700;transition:all .1s linear;display:flex}#btn-refresh-data:hover{background-color:var(--color-bg-secondary-dark);color:var(--color-text)}#btn-refresh-data .material-symbols-outlined{margin-bottom:.5px;font-size:18px}.sql-console-wrapper{flex-direction:column;height:100%;display:flex}.sql-editor{resize:vertical;border:none;border-bottom:1px var(--color-border) solid;background-color:var(--color-bg-primary);width:100%;height:200px;min-height:100px;color:var(--color-text);outline:none;padding:16px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:13px}.sql-editor:focus{background-color:#fcfcfc}.table-container{scrollbar-width:none;-ms-overflow-style:none;background-color:#fff;flex:1;width:100%;min-width:0;overflow:auto}.table-container::-webkit-scrollbar{display:none}.data-table{border-collapse:separate;border-spacing:0;-webkit-user-select:none;user-select:none;width:max-content;min-width:100%}.data-table input,.data-table select{-webkit-user-select:text;user-select:text;box-sizing:border-box}.data-table th,.data-table td{text-align:left;border-bottom:1px var(--color-border-soft) solid;border-right:1px var(--color-border-soft) solid;white-space:nowrap;cursor:cell;height:24px;padding:8px 16px;font-size:13px;position:relative}.data-table th:last-child,.data-table td:last-child{border-color:#2c68ec40}.data-table th{background-color:var(--color-primary);color:var(--color-bg-primary);text-transform:uppercase;letter-spacing:.5px;z-index:10;border-bottom:1px var(--color-border) solid;box-shadow:0 1px 0 var(--color-border);cursor:default;border-right:1px solid #fff3;font-size:11px;font-weight:600;position:sticky;top:0}.data-table td.cell-in-range{--shadow-t:inset 0 0 0 0 transparent;--shadow-b:inset 0 0 0 0 transparent;--shadow-l:inset 0 0 0 0 transparent;--shadow-r:inset 0 0 0 0 transparent;box-shadow:var(--shadow-t), var(--shadow-b), var(--shadow-l), var(--shadow-r);background-color:#dbeafe}.data-table td.range-top{--shadow-t:inset 0 2px 0 0 var(--color-primary)}.data-table td.range-bottom{--shadow-b:inset 0 -2px 0 0 var(--color-primary)}.data-table td.range-left{--shadow-l:inset 2px 0 0 0 var(--color-primary)}.data-table td.range-right{--shadow-r:inset -2px 0 0 0 var(--color-primary)}.data-table td.cell-selected{z-index:5;box-shadow:inset 0 0 0 2px var(--color-primary);background-color:#fff}.data-table td.row-header,.data-table th.row-header{z-index:9;background-color:var(--color-bg-secondary);color:var(--color-text-soft);text-align:center;border-right:1px var(--color-border) solid;width:32px;min-width:32px;padding:8px 4px;font-weight:500;position:sticky;left:0}.data-table th.row-header{z-index:11;background-color:var(--color-primary);color:var(--color-bg-primary)}.data-table td.cell-edited{color:#b45309;background-color:#fffbeb;font-weight:700}.data-table td.cell-error{background-color:#fef2f2}.data-table td.cell-error:not(.cell-in-range):not(.cell-selected){box-shadow:inset 0 0 0 2px #ef4444}.data-table tr.row-deleted td{text-decoration:line-through;color:#ef4444!important;background-color:#fee2e2!important}.data-table td.ghost-row{color:var(--color-text-soft);background-color:#f8fafc;font-style:italic}.data-table td input,.data-table td select{box-sizing:border-box;width:100%;height:100%;box-shadow:var(--ring-primary-2);background-color:#fff;border:none;outline:none;padding:0 16px;font-family:inherit;font-size:13px;position:absolute;top:0;left:0}.data-table tbody tr:hover{background-color:var(--color-bg-secondary)}.context-menu{background-color:var(--color-bg-primary);border:1px var(--color-border) solid;z-index:9999;border-radius:6px;flex-direction:column;min-width:150px;padding:4px;display:flex;position:absolute;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}.context-menu-item{color:var(--color-text);cursor:pointer;border-radius:4px;align-items:center;gap:8px;padding:8px 12px;font-size:13px;display:flex}.context-menu-item:hover{background-color:var(--color-bg-secondary)}.context-menu-item.danger{color:#ef4444}.context-menu-item.danger:hover{background-color:#fef2f2}.resizer{cursor:col-resize;-webkit-user-select:none;user-select:none;z-index:10;width:8px;height:100%;position:absolute;top:0;right:-4px}.resizer:hover,.resizer:active{background-color:var(--color-primary);opacity:.5}.cell-expand-btn{cursor:pointer;color:var(--color-text-soft);border:1px var(--color-border) solid;z-index:10;background-color:#fff;border-radius:4px;justify-content:center;align-items:center;padding:3px;font-size:14px;transition:all .1s;display:flex;position:absolute;top:50%;right:6px;transform:translateY(-50%);box-shadow:0 2px 4px #0000000d}.cell-expand-btn:hover{color:var(--color-primary);border-color:var(--color-primary)}#modal-editor-overlay{-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:9999;background-color:#0f172a66;justify-content:center;align-items:center;width:100vw;height:100vh;display:flex;position:fixed;top:0;left:0}.modal-editor-container{background-color:var(--color-bg-primary);border-radius:12px;flex-direction:column;width:600px;max-width:90vw;height:500px;max-height:90vh;display:flex;overflow:hidden;box-shadow:0 10px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.modal-header{border-bottom:1px var(--color-border) solid;color:var(--color-text);align-items:center;gap:8px;padding:16px 20px;display:flex}.modal-header h3{margin:0;font-size:16px;font-weight:600}.modal-header .material-symbols-outlined{color:var(--color-primary)}#modal-textarea{resize:none;color:var(--color-text);background-color:var(--color-bg-secondary-dark);border:none;outline:none;flex:1;padding:20px;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:13px}#modal-textarea:focus{background-color:#fff}.modal-footer{border-top:1px var(--color-border) solid;background-color:var(--color-bg-secondary);justify-content:flex-end;gap:12px;padding:16px 20px;display:flex}.modal-footer button{cursor:pointer;border:1px var(--color-border) solid;color:var(--color-text);background-color:#fff;border-radius:6px;padding:8px 16px;font-size:13px;font-weight:500;transition:all .2s}.modal-footer button:hover{background-color:var(--color-bg-secondary-dark)}.modal-footer button.primary{background-color:var(--color-primary);color:#fff;border-color:var(--color-primary)}.modal-footer button.primary:hover{background-color:var(--color-primary-dark)}