I want to experiment with a few interesting OS integrations, but first let's get an app for that - a simple CSV viewer is Svelte.
When you start the app, it will open a file dialog and ask you to select one or more CSV files to open. Then it will open a new window for each selected file.
I picked a few CSV example files with Taylor Swift lyrics from Kaggle and put them into samples
subfolder.
I'll be using d3-dsv
to parse CSV files. It's part of the D3, but it can be used separately, so npm install d3-dsv
.
index.js
First, we need to popup the dialog to select the CSV files.
let { app, BrowserWindow, dialog } = require("electron")
async function createWindow() {
let { canceled, filePaths } = await dialog.showOpenDialog({
properties: ["openFile", "multiSelections", "showHiddenFiles"],
filters: [
{ name: "CSV files", extensions: ["csv"] },
{ name: "All Files", extensions: ["*"] }
],
message: "Select a CSV file to open",
defaultPath: `${__dirname}/samples`,
})
if (canceled) {
app.quit()
}
for (let path of filePaths) {
let qs = new URLSearchParams({ path }).toString();
let win = new BrowserWindow({
width: 1024,
height: 768,
webPreferences: {
preload: `${__dirname}/preload.js`,
},
})
win.loadURL(`http://localhost:5000/?${qs}`)
}
}
app.on("ready", createWindow)
app.on("window-all-closed", () => {
app.quit()
})
As I mentioned before, this is Electron API weirdness. File dialogs are really a frontend concern, so logically they should go to the frontend process, but Electron API moves them to the backend, so we have to jump through a few hoops here.
For a small change from the hex editor, we setup default filter to only show *.csv
files, it can be overridden by the user through the OS-specific filter dropdown.
preload.js
let fs = require("fs")
let { contextBridge } = require("electron")
let q = new URLSearchParams(window.location.search)
let path = q.get("path")
let data = fs.readFileSync(path, "utf8")
contextBridge.exposeInMainWorld(
"api", { path, data }
)
A small change from the hex editor, we want to return a String
, not a Buffer
, so we assume CSV is in UTF8. If it's not, well, it's 21st century, you should have fixed that already.
src/App.svelte
And now for a very simple CSV viewer - we just dump everything into a simple HTML table, with no special handling of headers, or data types, or anything.
<script>
import {csvParseRows} from "d3-dsv"
let data = csvParseRows(window.api.data)
let fileName = window.api.path.split("/").slice(-1)[0]
let title = `CSV Viewer - ${fileName}`
</script>
<h1>CSV Viewer</h1>
<table>
{#each data as row}
<tr>
{#each row as column}
<td>{column}</td>
{/each}
</tr>
{/each}
</table>
<svelte:head>
<title>{title}</title>
</svelte:head>
<style>
:global(body) {
margin: 0;
background-color: #444;
color: #fff;
}
tr {
text-align: center;
}
</style>
Results
Here's the results:
Now that we have a base app, we'll be adding a few interesting enhancements to it over the next few episodes.
As usual, all the code for the episode is here.
Top comments (0)