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
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
Now we need to edit rollup.config.js
, first importing this plugin:
import copy from 'rollup-plugin-copy';
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/' },
]
}),
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>
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)
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>
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;
}
Result
Here's the results:
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.
Top comments (0)