DEV Community

Tomasz Wegrzanowski
Tomasz Wegrzanowski

Posted on

Electron Adventures: Episode 44: File Icons

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:

$ npm i file-icons-js
Enter fullscreen mode Exit fullscreen mode

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.

$ npm i rollup-plugin-copy
Enter fullscreen mode Exit fullscreen mode

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

import copy from 'rollup-plugin-copy';
Enter fullscreen mode Exit fullscreen mode

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

        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/' },
            ]
        }),
Enter fullscreen mode Exit fullscreen mode

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.

<!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>
Enter fullscreen mode Exit fullscreen mode

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).

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

  $: iconClasses = getClassWithColor(file.name)
Enter fullscreen mode Exit fullscreen mode

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

<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>
Enter fullscreen mode Exit fullscreen mode

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.

  .icon {
    display: inline-block;
    min-width: 1em;
  }
Enter fullscreen mode Exit fullscreen mode

Result

Here's the results:

Episode 44 Screenshot

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.

Discussion (0)