Skip to content

Commit fd13d43

Browse files
authored
Add web demo options to load example file or load from a URL (nightlark#69)
* Add web demo option to load an example file * Give a hover and drag effect for the Choose MSI button
1 parent 39fcdac commit fd13d43

File tree

3 files changed

+100
-14
lines changed

3 files changed

+100
-14
lines changed

docs/_static/example.msi

12 KB
Binary file not shown.

docs/_static/msi_viewer.js

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class MSIViewer {
2828
this.streamsContent = document.getElementById('streams-content');
2929
this.tabButtons = document.querySelectorAll('.tab-button');
3030
this.tabPanes = document.querySelectorAll('.tab-pane');
31+
this.loadExampleFileButton = document.getElementById('load-example-file-button');
3132
}
3233

3334
// Set up event listeners
@@ -43,6 +44,9 @@ class MSIViewer {
4344
this.switchTab(tabName);
4445
});
4546
});
47+
48+
// New file loading buttons
49+
this.loadExampleFileButton.addEventListener('click', this.handleLoadExampleFile.bind(this));
4650
}
4751

4852
// Switch between tabs
@@ -100,18 +104,14 @@ class MSIViewer {
100104
}
101105
}
102106

103-
// Handle file selection
104-
async handleFileSelect(event) {
105-
if (!this.fileInput.files || this.fileInput.files.length === 0) return;
106-
107-
const file = this.fileInput.files[0];
108-
this.currentFileName = file.name;
107+
// Load MSI file from ArrayBuffer (used for file input, example, and URL)
108+
async loadMsiFileFromArrayBuffer(arrayBuffer, fileName = 'uploaded.msi') {
109+
this.currentFileName = fileName;
109110
this.loadingIndicator.style.display = 'block';
110111
this.loadingIndicator.textContent = 'Reading MSI file...';
111112

112113
try {
113114
// Read the file as an ArrayBuffer
114-
const arrayBuffer = await file.arrayBuffer();
115115
const msiBinaryData = new Uint8Array(arrayBuffer);
116116

117117
// Write the file to Pyodide's virtual file system
@@ -151,6 +151,31 @@ class MSIViewer {
151151
}
152152
}
153153

154+
// Handle file selection
155+
async handleFileSelect(event) {
156+
if (!this.fileInput.files || this.fileInput.files.length === 0) return;
157+
158+
const file = this.fileInput.files[0];
159+
const arrayBuffer = await file.arrayBuffer();
160+
await this.loadMsiFileFromArrayBuffer(arrayBuffer, file.name);
161+
}
162+
163+
// Handle loading the example file from the server
164+
async handleLoadExampleFile() {
165+
const exampleUrl = '_static/example.msi';
166+
this.loadingIndicator.style.display = 'block';
167+
this.loadingIndicator.textContent = 'Fetching example file...';
168+
try {
169+
const response = await fetch(exampleUrl);
170+
if (!response.ok) throw new Error(`Failed to fetch example file (${response.status})`);
171+
const arrayBuffer = await response.arrayBuffer();
172+
await this.loadMsiFileFromArrayBuffer(arrayBuffer, 'example.msi');
173+
} catch (error) {
174+
this.loadingIndicator.textContent = `Error loading example file: ${error.message}`;
175+
console.error('Error loading example file:', error);
176+
}
177+
}
178+
154179
// Load files list from MSI
155180
async loadFilesList() {
156181
const filesData = await this.pyodide.runPythonAsync(`

docs/msi_viewer.md

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Behind the scenes, it is running [pymsi](https://github.com/nightlark/pymsi/) us
66

77
<div id="msi-viewer-app">
88
<div class="file-selector">
9+
<div style="margin-bottom: 1rem;">
10+
<button id="load-example-file-button" type="button" class="example-file-btn">Load example file</button>
11+
</div>
912
<div class="file-input-container">
1013
<input type="file" id="msi-file-input" accept=".msi" />
1114
<label for="msi-file-input" class="file-input-label">
@@ -93,11 +96,21 @@ Behind the scenes, it is running [pymsi](https://github.com/nightlark/pymsi/) us
9396
display: inline-block;
9497
}
9598

99+
.file-input-container.dragover .file-input-label {
100+
background: #005a9e;
101+
color: #e3f2fd;
102+
border: 2px solid #90caf9;
103+
box-shadow: 0 2px 16px 0 rgba(0, 122, 204, 0.22);
104+
}
105+
96106
#msi-file-input {
97107
position: absolute;
98108
opacity: 0;
99109
width: 100%;
100110
height: 100%;
111+
left: 0;
112+
top: 0;
113+
z-index: 2;
101114
cursor: pointer;
102115
}
103116

@@ -111,17 +124,21 @@ Behind the scenes, it is running [pymsi](https://github.com/nightlark/pymsi/) us
111124
border-radius: 6px;
112125
cursor: pointer;
113126
font-weight: 500;
114-
transition: background-color 0.2s ease;
127+
transition: background-color 0.2s, box-shadow 0.2s, border 0.2s, color 0.2s;
115128
border: 2px solid transparent;
129+
box-shadow: none;
130+
position: relative;
131+
z-index: 1;
116132
}
117133

118-
.file-input-label:hover {
119-
background: #005a9e;
120-
}
121-
134+
.file-input-label:hover,
135+
.file-input-container:hover .file-input-label,
122136
.file-input-label:focus-within {
123-
outline: 2px solid #007acc;
124-
outline-offset: 2px;
137+
background: #005a9e;
138+
color: #e3f2fd;
139+
border: 2px solid #90caf9;
140+
box-shadow: 0 2px 12px 0 rgba(0, 122, 204, 0.18);
141+
outline: none;
125142
}
126143

127144
#loading-indicator {
@@ -214,7 +231,51 @@ Behind the scenes, it is running [pymsi](https://github.com/nightlark/pymsi/) us
214231
overflow-y: auto;
215232
border: 1px solid #ddd;
216233
}
234+
235+
.example-file-btn {
236+
font-size: 0.95em;
237+
padding: 0.3em 0.9em;
238+
background: #f5f5f5;
239+
color: #007acc;
240+
border: 1px solid #b0d4f1;
241+
border-radius: 4px;
242+
cursor: pointer;
243+
margin-bottom: 0.5rem;
244+
transition: background 0.2s, color 0.2s, border 0.2s;
245+
vertical-align: middle;
246+
}
247+
.example-file-btn:hover,
248+
.example-file-btn:focus {
249+
background: #e3f2fd;
250+
color: #005a9e;
251+
border-color: #90caf9;
252+
outline: none;
253+
}
217254
</style>
255+
<script>
256+
// filepath: pymsi/docs/msi_viewer.md (inline script)
257+
document.addEventListener('DOMContentLoaded', function () {
258+
var fileInputContainer = document.querySelector('.file-input-container');
259+
if (!fileInputContainer) return;
260+
261+
// Highlight on drag over
262+
fileInputContainer.addEventListener('dragenter', function (e) {
263+
e.preventDefault();
264+
fileInputContainer.classList.add('dragover');
265+
});
266+
fileInputContainer.addEventListener('dragover', function (e) {
267+
e.preventDefault();
268+
fileInputContainer.classList.add('dragover');
269+
});
270+
fileInputContainer.addEventListener('dragleave', function (e) {
271+
if (e.relatedTarget && fileInputContainer.contains(e.relatedTarget)) return;
272+
fileInputContainer.classList.remove('dragover');
273+
});
274+
fileInputContainer.addEventListener('drop', function (e) {
275+
fileInputContainer.classList.remove('dragover');
276+
});
277+
});
278+
</script>
218279

219280
<!-- Include the Pyodide script -->
220281
<script type="text/javascript" src="https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.js"></script>

0 commit comments

Comments
 (0)