sqlite-wasm-viewer 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,8 @@ A simple web-based SQLite browser that lets you inspect SQLite databases created
4
4
 
5
5
  ![Viewer](screenshot.png)
6
6
 
7
+ Demo: https://sqlite-wasm-viewer.mysticeggs.xyz/demo/
8
+
7
9
  # Installation
8
10
  ```
9
11
  npm install --save sqlite-wasm-viewer
package/dist/state.js CHANGED
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.isDirty = isDirty;
8
8
  exports.selectCell = selectCell;
9
9
  exports.selectTable = selectTable;
10
+ exports.selectedCell = selectedCell;
10
11
  exports.selectedTable = selectedTable;
11
12
  exports.setDirty = setDirty;
12
13
  var Bus = _interopRequireWildcard(require("./bus"));
@@ -20,6 +21,9 @@ var _state = {
20
21
  function selectedTable() {
21
22
  return _state.selectedTable;
22
23
  }
24
+ function selectedCell() {
25
+ return _state.selectedCell;
26
+ }
23
27
  function isDirty() {
24
28
  return _state.dirty;
25
29
  }
@@ -28,6 +32,11 @@ function selectCell(cell) {
28
32
  Bus.emit('cell-selected', cell);
29
33
  }
30
34
  function selectTable(table) {
35
+ var _state$selectedTable;
36
+ var hasChanged = ((_state$selectedTable = _state.selectedTable) === null || _state$selectedTable === void 0 ? void 0 : _state$selectedTable.tableName) !== table.tableName;
37
+ if (hasChanged) {
38
+ selectCell(null);
39
+ }
31
40
  _state.selectedTable = table;
32
41
  Bus.emit('table-selected', table);
33
42
  }
package/dist/styles.css CHANGED
@@ -4,10 +4,14 @@
4
4
  left: 0;
5
5
  right: 0;
6
6
  bottom: 0;
7
- background-color: whitesmoke;
7
+ background: linear-gradient(180deg, #f4f7fb 0%, #edf2f8 100%);
8
8
  display: flex;
9
- padding: 10px;
10
- padding-top: 20px;
9
+ padding: 12px;
10
+ padding-top: 44px;
11
+ gap: 10px;
12
+ color: #111827;
13
+ font-family: Inter, "Segoe UI", Roboto, Arial, sans-serif;
14
+ font-size: 13px;
11
15
  }
12
16
 
13
17
  #viewer * {
@@ -15,22 +19,40 @@
15
19
  }
16
20
 
17
21
  #viewer .viewHeader {
18
- max-height: 20px;
19
- flex-basis: 20px;
22
+ max-height: 34px;
23
+ flex-basis: 34px;
20
24
  flex-shrink: 0;
21
- line-height: 1.1rem;
22
- padding: 8px;
25
+ line-height: 1.2rem;
26
+ padding: 8px 10px;
23
27
  display: flex;
24
28
  align-items: center;
25
29
  gap: 8px;
26
- background-color: lightgray;
30
+ border-bottom: 1px solid #e5e7eb;
31
+ background: linear-gradient(180deg, #ffffff 0%, #f9fafb 100%);
32
+ font-weight: 600;
33
+ color: #334155;
27
34
  }
28
35
 
29
36
  #viewer #close_btn {
30
37
  position: absolute;
31
- left: 10px;
32
- top: 0px;
38
+ top: 12px;
39
+ left: 14px;
40
+ z-index: 5;
41
+ padding: 2px 10px;
42
+ min-height: 26px;
43
+ border-radius: 999px;
33
44
  cursor: pointer;
45
+ color: #334155;
46
+ background: #ffffff;
47
+ border: 1px solid #b8c6d9;
48
+ font-size: 12px;
49
+ line-height: 1.2;
50
+ box-shadow: 0 2px 6px rgba(15, 23, 42, 0.08);
51
+ }
52
+
53
+ #viewer #close_btn:hover {
54
+ background: #f8fafc;
55
+ border-color: #94a3b8;
34
56
  }
35
57
 
36
58
  #viewer #db_list {
@@ -38,24 +60,33 @@
38
60
  min-width: 180px;
39
61
  max-width: 750px;
40
62
  flex: 0 0 auto;
41
- padding: 5px;
63
+ padding: 0;
42
64
  background-color: darkgray;
43
65
  display: flex;
44
66
  flex-direction: column;
67
+ border: 1px solid #dbe2ea;
68
+ border-radius: 10px;
69
+ overflow: hidden;
70
+ background: #fff;
71
+ box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08);
45
72
  }
46
73
 
47
74
  #viewer #tree_root {
48
75
  flex-grow: 1;
49
- padding: 5px;
50
- background-color: darkgray;
76
+ padding: 0;
77
+ background-color: #fff;
51
78
  }
52
79
 
53
80
  #viewer #middle_panel {
54
- background-color: darkgray;
81
+ background: #fff;
55
82
  flex: 1;
56
83
  flex-basis: 800px;
57
84
  display: flex;
58
85
  flex-direction: column;
86
+ border: 1px solid #dbe2ea;
87
+ border-radius: 10px;
88
+ overflow: hidden;
89
+ box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08);
59
90
  }
60
91
 
61
92
  #viewer #right_panel {
@@ -63,31 +94,85 @@
63
94
  min-width: 180px;
64
95
  max-width: 500px;
65
96
  flex: 0 0 auto;
66
- padding: 5px;
67
- background-color: darkgray;
97
+ padding: 0;
98
+ background: transparent;
68
99
  display: flex;
69
100
  flex-direction: column;
70
- gap: 5px;
101
+ gap: 10px;
71
102
  }
72
103
 
73
104
  #viewer #right_panel > div {
74
105
  height: 33.33%;
106
+ border: 1px solid #dbe2ea;
107
+ border-radius: 10px;
108
+ overflow: hidden;
109
+ background: #fff;
110
+ box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08);
75
111
  }
76
112
 
77
113
  #viewer .resizeDragHandler {
78
- width: 8px;
114
+ width: 10px;
79
115
  flex-shrink: 0;
80
116
  cursor: col-resize;
117
+ position: relative;
81
118
  }
82
119
 
83
120
  #viewer .resizeDragHandler:hover::after {
84
- border: 2px solid gray;
85
- border-radius: 2px;
121
+ border: 2px solid #94a3b8;
122
+ border-radius: 999px;
86
123
  content: '';
87
124
  display: block;
88
- height: 80%;
125
+ height: 72%;
89
126
  margin: 0 auto;
90
127
  position: relative;
91
- top: 10%;
128
+ top: 14%;
92
129
  width: 0;
130
+ }
131
+
132
+ #viewer button,
133
+ #viewer input,
134
+ #viewer textarea {
135
+ font: inherit;
136
+ }
137
+
138
+ #viewer button {
139
+ border: 1px solid #cbd5e1;
140
+ border-radius: 6px;
141
+ background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
142
+ color: #1e293b;
143
+ padding: 4px 10px;
144
+ cursor: pointer;
145
+ transition: background-color 0.15s ease, border-color 0.15s ease;
146
+ }
147
+
148
+ #viewer button.panelActionBtn {
149
+ border-top-left-radius: 0;
150
+ border-top-right-radius: 0;
151
+ border-bottom-left-radius: 9px;
152
+ border-bottom-right-radius: 9px;
153
+ }
154
+
155
+ #viewer button:hover:not([disabled]) {
156
+ border-color: #94a3b8;
157
+ background: #f8fafc;
158
+ }
159
+
160
+ #viewer button[disabled] {
161
+ opacity: 0.55;
162
+ cursor: not-allowed;
163
+ }
164
+
165
+ #viewer input,
166
+ #viewer textarea {
167
+ border: 1px solid #cbd5e1;
168
+ background: #fff;
169
+ color: #111827;
170
+ padding: 6px 8px;
171
+ }
172
+
173
+ #viewer input:focus,
174
+ #viewer textarea:focus {
175
+ outline: none;
176
+ border-color: #60a5fa;
177
+ box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.18);
93
178
  }
package/dist/viewer.js CHANGED
@@ -30,7 +30,7 @@ var Viewer = /*#__PURE__*/function () {
30
30
  var _this = this;
31
31
  this._container = document.createElement('div');
32
32
  this._container.id = 'viewer';
33
- var closeBtn = document.createElement('div');
33
+ var closeBtn = document.createElement('button');
34
34
  closeBtn.id = 'close_btn';
35
35
  closeBtn.innerText = 'Close';
36
36
  closeBtn.onclick = function () {
@@ -24,9 +24,14 @@ var EditCellView = /*#__PURE__*/function () {
24
24
  this.rootEl = rootEl;
25
25
  this.buildDom();
26
26
  Bus.listen('cell-selected', function (cell) {
27
- _this.currentCell = cell;
28
- _this.textArea.value = cell.value;
29
- _this.textArea.select();
27
+ if (cell) {
28
+ _this.textArea.value = cell.value;
29
+ _this.textArea.select();
30
+ _this.textArea.placeholder = '';
31
+ } else {
32
+ _this.textArea.value = '';
33
+ _this.textArea.placeholder = 'Select cell to edit...';
34
+ }
30
35
  });
31
36
  }
32
37
  _createClass(EditCellView, [{
@@ -39,10 +44,12 @@ var EditCellView = /*#__PURE__*/function () {
39
44
  header.innerText = 'Edit Cell';
40
45
  container.appendChild(header);
41
46
  this.textArea = document.createElement('textarea');
47
+ this.textArea.placeholder = 'Select cell to edit...';
42
48
  this.textArea.id = 'execute_sql_textarea';
43
49
  container.appendChild(this.textArea);
44
50
  var executeBtn = document.createElement('button');
45
51
  executeBtn.innerText = 'Apply';
52
+ executeBtn.classList.add('panelActionBtn');
46
53
  executeBtn.onclick = this.handleApplyEdit.bind(this);
47
54
  container.appendChild(executeBtn);
48
55
  this.rootEl.appendChild(container);
@@ -1,23 +1,30 @@
1
1
  #execute_sql_container {
2
2
  display: flex;
3
3
  flex-direction: column;
4
+ height: 100%;
4
5
  }
5
6
 
6
7
  #execute_sql_editor {
7
8
  position: relative;
8
- background-color: white;
9
- height: 300px;
9
+ background-color: #fff;
10
+ height: 100%;
10
11
  }
11
12
 
12
13
  #execute_sql_textarea {
13
14
  resize: none;
14
- height: 300px;
15
- background-color: white;
15
+ height: 100%;
16
+ min-height: 150px;
17
+ background: #f8fafc;
16
18
  overflow: auto;
17
19
  white-space: nowrap;
18
- font-size: 10pt;
19
- font-family: monospace;
20
- line-height: 1.5;
20
+ font-size: 12px;
21
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
22
+ line-height: 1.45;
21
23
  tab-size: 2;
22
- caret-color: black;
24
+ caret-color: #111827;
25
+ color: #0f172a;
26
+ border: 0;
27
+ border-top: 1px solid #e5e7eb;
28
+ border-bottom: 1px solid #e5e7eb;
29
+ border-radius: 0;
23
30
  }
@@ -32,6 +32,7 @@ var ExecuteSQLView = /*#__PURE__*/function () {
32
32
  container.appendChild(this.textArea);
33
33
  var executeBtn = document.createElement('button');
34
34
  executeBtn.innerText = 'Execute SQL';
35
+ executeBtn.classList.add('panelActionBtn');
35
36
  executeBtn.onclick = this.handleExecuteSql.bind(this);
36
37
  container.appendChild(executeBtn);
37
38
  this.rootEl.appendChild(container);
@@ -1,47 +1,51 @@
1
1
  #execute_sql_container {
2
2
  display: flex;
3
3
  flex-direction: column;
4
+ height: 100%;
4
5
  }
5
6
 
6
7
  #execute_sql_editor {
7
8
  position: relative;
8
- background-color: white;
9
- height: 300px;
9
+ background-color: #fff;
10
+ height: 100%;
10
11
  }
11
12
 
12
13
  #execute_sql_textarea, #execute_sql_highlighting {
13
14
  resize: none;
14
- height: 300px;
15
- background-color: white;
15
+ height: 100%;
16
+ min-height: 150px;
17
+ background: #f8fafc;
16
18
  overflow: auto;
17
19
  white-space: nowrap;
18
- font-size: 10pt;
19
- font-family: monospace;
20
- line-height: 1.5;
20
+ font-size: 12px;
21
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
22
+ line-height: 1.45;
21
23
  tab-size: 2;
22
- caret-color: black;
24
+ caret-color: #111827;
25
+ color: #0f172a;
23
26
  }
24
27
 
25
28
  #execute_sql_highlighting {
26
29
  z-index: 0;
27
30
  margin: 0;
28
- padding: 2px;
31
+ padding: 8px;
32
+ border-top: 1px solid #e5e7eb;
33
+ border-bottom: 1px solid #e5e7eb;
34
+ border-radius: 0;
29
35
  }
30
36
 
31
37
  .highlighting {
32
- color: blue;
38
+ color: #2563eb;
33
39
  }
34
40
 
35
41
  .sql-hl-keyword {
36
- color: purple;
37
- /* font-weight: 600; */
42
+ color: #7c3aed;
38
43
  }
39
44
 
40
45
  .sql-hl-special {
41
- color: black;
46
+ color: #0f172a;
42
47
  }
43
48
 
44
49
  .sql-hl-string {
45
- color: red;
46
- /* font-weight: 600; */
50
+ color: #dc2626;
47
51
  }
@@ -204,6 +204,6 @@ function createExplorerView(rootEl, viewEl) {
204
204
  if (!_explorerView) {
205
205
  _explorerView = new ExplorerView(rootEl, viewEl);
206
206
  } else {
207
- console.warn('ExplorerView is already created');
207
+ // console.warn('ExplorerView is already created');
208
208
  }
209
209
  }
@@ -1,19 +1,21 @@
1
1
  #explorer_tree {
2
- padding: 8px;
3
- padding-left: 20px;
2
+ padding: 8px 8px 8px 20px;
4
3
  overflow-y: auto;
5
4
  scrollbar-gutter: stable;
5
+ background: #fff;
6
6
  }
7
7
 
8
8
  #explorer_tree .item {
9
- height: 20px;
9
+ height: 26px;
10
10
  white-space: nowrap;
11
11
  text-overflow: ellipsis;
12
- background-color: darkgray;
12
+ background: transparent;
13
+ border-radius: 6px;
14
+ color: #334155;
13
15
  }
14
16
 
15
17
  #explorer_tree .item > .label {
16
- padding: 2px 4px;
18
+ padding: 4px 8px;
17
19
  overflow: hidden;
18
20
  text-overflow: ellipsis;
19
21
  }
@@ -24,14 +26,15 @@
24
26
 
25
27
  #explorer_tree .expand {
26
28
  position: absolute;
27
- top: 1px;
29
+ top: 3px;
28
30
  left: -20px;
29
31
  width: 20px;
30
32
  height: 20px;
31
33
  display: flex;
32
34
  align-items: center;
33
35
  justify-content: center;
34
- transition: all .1s ease-in;
36
+ color: #64748b;
37
+ transition: all 0.12s ease-in;
35
38
  }
36
39
 
37
40
  #explorer_tree .expanded {
@@ -43,16 +46,25 @@
43
46
  cursor: pointer;
44
47
  }
45
48
 
49
+ #explorer_tree .table:hover,
50
+ #explorer_tree .db:hover {
51
+ background: #f1f5f9;
52
+ }
53
+
46
54
  #explorer_tree .table.selected {
47
- background-color: rgb(128, 128, 128);
55
+ background: #e2e8f0;
56
+ color: #0f172a;
57
+ font-weight: 600;
48
58
  }
49
59
 
50
60
  #viewer #full_label {
51
61
  position: absolute;
52
62
  pointer-events: none;
53
63
  z-index: 99999;
54
- border: 1px solid gray;
55
- background-color: darkgray;
56
- padding: 2px 4px;
57
- border-radius: 2px;
64
+ border: 1px solid #cbd5e1;
65
+ background-color: #fff;
66
+ color: #0f172a;
67
+ padding: 4px 8px;
68
+ border-radius: 6px;
69
+ box-shadow: 0 6px 20px rgba(15, 23, 42, 0.16);
58
70
  }
@@ -2,9 +2,19 @@
2
2
  flex-grow: 1;
3
3
  display: flex;
4
4
  flex-direction: column;
5
+ height: 100%;
5
6
  }
6
7
 
7
8
  #query_log_text {
8
9
  resize: none;
9
10
  height: 100%;
11
+ min-height: 150px;
12
+ background: #f8fafc;
13
+ color: #1e293b;
14
+ border: 0;
15
+ border-top: 1px solid #e5e7eb;
16
+ border-radius: 0;
17
+ font-size: 12px;
18
+ line-height: 1.45;
19
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
10
20
  }
@@ -310,6 +310,6 @@ function createTableView(rootEl) {
310
310
  if (!_tableView) {
311
311
  _tableView = new TableView(rootEl);
312
312
  } else {
313
- console.warn('TableView is already created');
313
+ // console.warn('TableView is already created');
314
314
  }
315
315
  }
@@ -1,5 +1,5 @@
1
1
  #table_view {
2
- padding: 5px;
2
+ padding: 0;
3
3
  flex: 1;
4
4
  position: relative;
5
5
  overflow: hidden;
@@ -8,77 +8,101 @@
8
8
  }
9
9
 
10
10
  #table_view_header {
11
- max-height: 20px;
12
- flex-basis: 20px;
11
+ max-height: 34px;
12
+ flex-basis: 34px;
13
13
  left: 0;
14
14
  right: 0;
15
15
  position: sticky;
16
16
  line-height: 1.1rem;
17
- padding: 8px;
18
- background-color: lightgray;
17
+ padding: 8px 10px;
18
+ background: linear-gradient(180deg, #ffffff 0%, #f9fafb 100%);
19
19
  }
20
20
 
21
21
  #table_view_header_title {
22
- padding: 8px;
22
+ padding-right: 8px;
23
23
  }
24
24
 
25
25
  #table_container {
26
- overflow-y: scroll;
27
- display: flex;
26
+ overflow: auto;
27
+ flex: 1;
28
+ background: #fff;
28
29
  }
29
30
 
30
31
  #table_container table {
31
- flex: 1;
32
32
  table-layout: fixed;
33
33
  width: 100%;
34
- background-color: whitesmoke;
34
+ background: #fff;
35
35
  border-collapse: collapse;
36
36
  border-spacing: 0;
37
37
  }
38
38
 
39
39
  #table_container tbody {
40
- flex: 1;
41
- overflow-y: scroll;
42
40
  position: relative;
43
41
  }
44
42
 
45
43
  #table_container .columnHeaderCell {
46
- height: 60px;
44
+ height: 62px;
47
45
  position: sticky;
48
46
  top: 0;
49
- background-color: darkgray;
47
+ padding: 6px;
48
+ background: #f8fafc;
50
49
  z-index: 2;
50
+ color: #334155;
51
+ font-weight: 600;
52
+ text-overflow: ellipsis;
53
+ overflow: hidden;
51
54
  }
52
55
 
53
56
  #table_container .columnFilterCell {
54
- padding-top: 5px;
57
+ padding-top: 6px;
58
+ text-overflow: ellipsis;
59
+ overflow: hidden;
55
60
  }
56
61
 
57
62
  #table_container .columnFilterCell input {
58
- width: calc(100% - 8px);
63
+ width: 100%;
64
+ box-sizing: border-box;
65
+ font-size: 12px;
59
66
  }
60
67
 
61
68
  #table_container td, #table_container .columnHeaderCell {
62
- border: 1px solid lightgray;
69
+ border: 1px solid #e2e8f0;
63
70
  }
64
71
 
65
72
  #table_container td.selected {
66
- background-color: lightslategray;
67
- color: white;
73
+ background: #2563eb;
74
+ color: #fff;
68
75
  }
69
76
 
70
77
  #table_container td div {
71
78
  height: 40px;
72
79
  box-sizing: border-box;
73
- padding: 4px;
80
+ padding: 10px 8px;
74
81
  text-overflow: ellipsis;
75
82
  overflow: hidden;
76
83
  white-space: pre;
77
- font-size: 15px;
78
- line-height: 1.1em;
84
+ font-size: 13px;
85
+ line-height: 1.2em;
86
+ }
87
+
88
+ #table_container tbody tr:nth-child(even) td:not(.selected) {
89
+ background: #fcfdff;
90
+ }
91
+
92
+ #table_container tbody tr:hover td:not(.selected) {
93
+ background: #eff6ff;
94
+ }
95
+
96
+ #table_container tbody tr:hover td.selected {
97
+ background: #2563eb;
79
98
  }
80
99
 
81
100
  #table_container .nullValue {
82
101
  font-style: italic;
83
- color: gray;
102
+ color: #64748b;
103
+ }
104
+
105
+ ::placeholder {
106
+ color: #959595; /* Use any color format (HEX, RGB, Name) */
107
+ opacity: 1; /* Required for Firefox to show full color */
84
108
  }
package/package.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "name": "sqlite-wasm-viewer",
3
- "version": "1.1.1",
4
- "description": "An SQLite OPFS database viewer that enables database inspection and SQL command execution.",
3
+ "version": "1.2.0",
4
+ "description": "Browser SQLite OPFS viewer for @sqlite.org/sqlite-wasm: inspect OPFS-backed databases, run SQL, and filter tables.",
5
5
  "main": "dist/index.js",
6
+ "homepage": "https://github.com/mifozski/sqlite-wasm-viewer#readme",
7
+ "bugs": {
8
+ "url": "https://github.com/mifozski/sqlite-wasm-viewer/issues"
9
+ },
6
10
  "scripts": {
7
11
  "build": "yarn build-transpile && yarn build-copy-css",
8
12
  "build-transpile": "babel src --extensions .ts --out-dir=dist --presets=@babel/env,@babel/typescript",
@@ -11,10 +15,16 @@
11
15
  },
12
16
  "keywords": [
13
17
  "sqlite",
18
+ "sqlite-wasm",
14
19
  "opfs",
20
+ "opfs-viewer",
15
21
  "wasm",
22
+ "viewer",
23
+ "browser",
16
24
  "sql",
17
- "database"
25
+ "database",
26
+ "inspector",
27
+ "sqlite-wasm-viewer"
18
28
  ],
19
29
  "author": {
20
30
  "name": "Andrey Efimov",