Electron Adventures: Episode 25: Orthodox File Manager Styling
Tags: electron, javascript
Published: 2021-08-19 00:15:24

We want to build something along the lines of an "[Orthodox File Manager](https://en.wikipedia.org/wiki/File_manager#Orthodox_file_managers)".

Browsers default to mouse interfaces, while file managers need to work with just keyboard, and have a lot of UI patterns that don't match what typical websites or webapps.

So we' need to implement this functionality yourselves.

### Orthodox File Manager UI

Let's do a simple interface with the following features, implementing highly simplified "Orthodox File Manager" interface:

* two panels, switching between them with TAB
* each panel is a list of files, UP and DOWN arrow move between them
* any number of files can be selected with SPACE
* various Fn keys popup various modals to perform common actions (on either selected files, or currently focused file if none are selected on given panel)
* each panel remembers which file was focused, but focused file in inactive file is not indicated

But before we even get there, let do just styling with completely static data, similar to how we created the terminal app!

### Data

I took static data from [Cat Ipsum](http://www.catipsum.com/).

Header and footer are both placeholders.

Here's `index.html`:

```html
<!DOCTYPE html>
<html>
  <head>
    <link href="app.css" rel="stylesheet" type="text/css" />
  </head>
  <body>
    <div class="ui">
      <header>
        File Manager
      </header>
      <div class="panel panel-left active">
        <div class="file selected">Cat.js</div>
        <div class="file selected">ipsum.js</div>
        <div class="file">dolor.js</div>
        <div class="file selected">sit.js</div>
        <div class="file selected">amet.js</div>
        <div class="file focused">walk.js</div>
        <div class="file">on.js</div>
        <div class="file">keyboard.js</div>
        <div class="file">hide.js</div>
        <div class="file">when.js</div>
        <div class="file">guests.js</div>
        <div class="file">come.js</div>
        <div class="file">over.js</div>
        <div class="file">play.js</div>
        <div class="file">with.js</div>
        <div class="file">twist.js</div>
        <div class="file">ties.js</div>
      </div>
      <div class="panel panel-right">
        <div class="file">Ask.png</div>
        <div class="file">to.png</div>
        <div class="file focused">be.png</div>
        <div class="file">pet.png</div>
        <div class="file selected">then.png</div>
        <div class="file selected">attack.png</div>
        <div class="file selected">owners.png</div>
        <div class="file selected">hand.png</div>
        <div class="file">need.png</div>
        <div class="file">to.png</div>
        <div class="file">chase.png</div>
        <div class="file">tail.png</div>
      </div>
      <footer>
        <button>F1 Help</button>
        <button>F2 Menu</button>
        <button>F3 View</button>
        <button>F4 Edit</button>
        <button>F5 Copy</button>
        <button>F6 Move</button>
        <button>F7 Mkdir</button>
        <button>F8 Delete</button>
        <button>F10 Quit</button>
      </footer>
    </div>
  </body>
</html>
```

It should be fairly self explanatory:

* we have 4 areas: `header`, `panel-left`, `panel-right`, `footer`
* each panel contains a lot of `file` items
* some `file` items can `selected` or `focused` or both
* only one of the panels will be `active` at a time

### Setting up basic styling

Terminals are traditionally white-on-black. File managers are traditionally white-on-blue. I did not make the rules.

```css
body {
  background-color: #226;
  color: #fff;
  font-family: monospace;
  margin: 0;
  font-size: 16px;
}
```

### Setting up grid

It's very easy to do this with `display: grid`:

```css
.ui {
  width: 100vw;
  height: 100vh;
  display: grid;
  grid-template-areas:
    "header header"
    "panel-left panel-right"
    "footer footer";
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto 1fr auto;
}
.ui header {
  grid-area: header;
}
.ui .panel-left {
  grid-area: panel-left;
}
.ui .panel-right {
  grid-area: panel-right;
}
.ui footer {
  grid-area: footer;
}
```

### Setting up item styling

These are some reasonable colors to indicate `selected` and `focused` states. Additionally selected files are bolded, something terminal-based file managers don't normally do.

```css
.ui .panel {
  background: #338;
  margin: 4px;
}
.panel .file.selected {
  color: #ff2;
  font-weight: bold;
}
.panel.active .file.focused {
  background-color: #66b;
}
```

### Styling header and footer

So far in this series I haven't used any CSS resets, so `button` needs a bunch of `inherit` rules. Most of the time I just nuke the whole CSS before starting, so then we wouldn't need any such rules:

```css
header {
  font-size: 24px;
  margin: 4px;
}
.ui footer {
  text-align: center;
}
button {
  font-family: inherit;
  font-size: inherit;
  background-color: #66b;
  color: inherit;
}
```

### How much should we follow tradition?

Orthodox File Managers come from terminal era. I think the basic concept of keyboard-controlled two-panel UI is still great, but some of their design decisions are based on limitations of terminal UIs.

The most obvious question to ask is if we want to use monospace font or not. Pretty much no non-terminal programs do that, and nobody minds. Even text editors like VSCode use regular sans font for their file management.

There's a long list of such questions we could have.

We might explore some of them in the future.

### Results

Here's the results:

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

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