Electron Adventures: Episode 44: File Icons
Tags: electron, svelte, javascript
Published: 2021-09-08 04:04:30

Let's make the file manager look a bit better. A good start is some icons for different file types.

This turned out to be much more complicated than I thought.

### Importing resources from node packages

Well first, let's install our package:

```shell
$ npm i file-icons-js
```

It's very easy to import Javascript from node packages - it works out of the box in every bundler.

So how to do that for CSS? And for font files? Unfortunately we'll need to mess up with rollup configuration. We're not doing anything complicated - we just want certain files from a node package to be copied to our build.

```shell
$ npm i rollup-plugin-copy
```

Now we need to edit `rollup.config.js`, first importing this plugin:

```javascript
import copy from 'rollup-plugin-copy';
```

And then in plugins section list what we're copying and where:

```javascript
		copy({
			targets: [
				{ src: 'node_modules/file-icons-js/css/', dest: 'public/build/file-icons-js/' },
				{ src: 'node_modules/file-icons-js/fonts/', dest: 'public/build/file-icons-js/' },
			]
		}),
```

### `public/index.html`

Now we need to tell our `index.html` to load that CSS file we just copied. As relative paths of CSS and fonts are the same as in the node package, font imports from that CSS files now just work.

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <link rel="stylesheet" href="/build/bundle.css">
    <link rel="stylesheet" href="/build/file-icons-js/css/style.css">
    <script src="/build/bundle.js"></script>
  </body>
</html>
```

Doing it a few times is fine, but every time you do this, that's another CSS import. If you'd rather serve a single CSS bundle, it will take some additional work.

### `src/File.svelte`

Fortunately the package is easy enough to use. Javascript imports just work out of the box, so we need to import one function, and call it reactively with the file's name. The package I'm using sort of wanted to add support for directory icons too, but that's not really working right now (and I should probably create an issue about this).

```javascript
  import { getClassWithColor } from "file-icons-js"

  $: iconClasses = getClassWithColor(file.name)
```

Then in the template I just add one span with the classes we got from the package:

```html
<div
  class="file"
  class:focused={focused}
  class:selected={selected}
  on:click|preventDefault={() => onclick()}
  on:contextmenu|preventDefault={() => onrightclick()}
  on:dblclick|preventDefault={() => ondoubleclick()}
  bind:this={node}
>
  {filySymbol(file)}<span class="icon {iconClasses}"></span>{file.name}
</div>
```

This mostly works, but there's no default icon - if file type is not recognized, or it's a directory, there's no icon at all.

This then makes files with icons and files without icons misaligned, so we need to add some `min-width` to make sure no-icon files just have equal amount of empty space there.

```css
  .icon {
    display: inline-block;
    min-width: 1em;
  }
```

### Result

Here's the results:

![Episode 44 Screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a42f0lqwos1q3z9k3t5d.png)

Is it great? Not really. Especially not having icons for directories, for unknown files, for symbolic links, and so on, makes this package not fit for what we're doing here. The colors also don't look great on the retro blue background we're using, but this is arguably our fault, and maybe we should switch to more modern VSCode grey.

So for the next episode I'll drop these icons, but it's an issue we might revisit sometime later.

In the next episode, we'll make our file manager do some filesystem operations!

As usual, [all the code for the episode is here](https://github.com/taw/electron-adventures/tree/master/episode-44-file-icons).