◆ フォルダ内のファイルをプレビューする
◆ ブラウザが色々なファイルに対応してるのでブラウザを使う
◆ file スキームは制限多いのでローカルで動かしたプログラムで HTML を事前に作る
◆ iframe でローカルのパスを指定して表示する

プレビューしたい

フォルダのファイル一覧を簡単にプレビューしたいです
フォルダにファイルが多いときにひとつずつ開いていくのはかなり面倒です

画像ならサムネ表示でいいですが テキストなど小さい表示だとわかりづらいのもあるので一度に見えるのはひとつでもいいのです
ひとつずつファイルを開いていくしかない操作が嫌なんです

高機能なエクスプローラ系ツールだとエクスプローラ上で選択しただけでプレビューできる機能がついてるのもあります
一つずつ選択していることに違いはないのですが
「ファイル開く→プログラムとファイルのロードを待つ→見る→閉じる→次を開く」
という操作がファイルを選択するだけで済むのは大きいです
ロードもファイルのみなので高速ですし
なにより同じツール内で次のを選択するだけで済むのは大きいです
別のプログラムで開かれると別画面になるわけなので画面の切り替わりがありますし 閉じた後に続きからの操作がしづらいです
同じツールで プレビューエリアに目を合わせたまま次を見たいなら⇩キーを押すだけというのはかなり使いやすいです

ただデフォルトのエクスプローラのままな PC が多いのでそういうツールが使えない環境も多いです
それに対応ファイルがそこまで多くなかったり拡張子ごとに自分で設定が必要だったりで準備がいります

考えてみるとブラウザに入れるとテキストでも HTML でも画像でも動画でも PDF でも大抵のファイルはプレビューしてくれるんですよね
ただフォルダを表示してもそれぞれのファイルのリンクが並ぶだけで一つずつ開いていく面倒さは変わりません
エクスプローラで開いてファイルごとに設定されたプログラムで開くかブラウザ上で見えるかの違いです

HTML と iframe でプレビューする

エクスプローラ系ツールのプレビュー機能をブラウザでできればいいのにと思ってプレビューツールを作ることにしました

とは言ってもブラウザでローカルの file スキーム周りの処理はほとんどできないです
fetch ができないのでフォルダを指定してその中のファイル一覧を取得はできません
ただ iframe で指定したパスのファイルを表示することはできるので 事前にパスを埋め込んだ HTML をローカルで開いて iframe の src を書き換えることでプレビューするようにしました

HTML を作るのはローカルにアクセスできる言語で作ります
Python とか C# も考えましたが私の環境だと WSL 含めれば全 PC で使える Node.js にしました
最悪 VSCode の devtools を使う方法もあるのでほとんどの環境で使えますし

HTML 生成

const fs = require("fs")
const path = require("path")

const esc = text => {
return text.replace(/["&<>]/g, e => {
return { '"': "&quot;", "&": "&amp;", "<": "&lt;", ">": "&gt;" }[e]
})
}

const tpl = items => `
<!doctype html>

<style>
body {
display: flex;
height: 100vh;
align-items: stretch;
margin: 0;
}
nav {
overflow: auto;
flex: none;
display: flex;
flex-flow: column;
padding: 10px;
border-right: 1px dotted gray;
}
nav a {
padding: 3px 12px;
font-size: 12px;
color: royalblue;
}
iframe {
flex: 1 1 0;
border: 3px solid cornflowerblue;
margin: 10px;
}
.selected {
background: #fffabd;
}
</style>

<nav>${
items.map(e => `<a href="${esc(e.path)}">${esc(e.name)}</a>`).join("\n")
}</nav>
<iframe></iframe>

<script>
const select = elem => {
for(const e of document.querySelectorAll(".selected")) {
e.classList.remove("selected")
}
const iframe = document.querySelector("iframe")
if(elem && elem.href) {
elem.classList.add("selected")
iframe.src = elem.href
} else {
iframe.src = ""
}
}
window.onclick = function(eve) {
if (eve.target.href) {
eve.preventDefault()
select(eve.target)
}
}
window.onkeydown = function(eve) {
const selected = document.querySelector(".selected")
const next_selected = (
!selected ?
document.querySelector("nav a")
: eve.key === "ArrowUp" ?
selected.previousElementSibling
: eve.key === "ArrowDown" ?
selected.nextElementSibling
:
null
)
if(next_selected) {
select(next_selected)
}
}
</script>
`.trim()

const main = dir => {
const dirpath = path.resolve(dir || ".")
const filenames = fs.readdirSync(dirpath)

const items = filenames.map(n => {
return {
name: n,
path: path.join(dirpath, n),
}
})

fs.writeFileSync("dirpreview.html", tpl(items))
}

main(process.argv[2])

このプログラムを使います
generate-dirpreview.js という名前だったら

node generate-dirpreview.js path\to\dir

のように引数でフォルダを指定します
省略するとカレントディレクトリです

実行すると dirpreview.html というファイルがカレントディレクトリに出力されます

表示

開くとこんな感じです

サイドバーにファイルリストが表示されてクリックすると iframe でプレビュー表示できます
上下キーで選択中のファイルを切り替えることができます

dprev-img2

フォルダもプレビューされますが フォルダをブラウザで開いたものと同じで そのフォルダの中を今回のプレビュー機能でプレビューすることはできません

dprev-img1