comic masterという自作のMac対応画像ビューアがあります
以前からバージョンアップしたところ
- フルスクリーンモードを追加(f)
- サムネイル表示モードを追加(t)
- 妻が来たモードを追加(e)
- ファイル名の表示、非表示機能を追加(n)
- 現在のページ数表示、非表示機能を追加(r)
フルスクリーンモード
electronのフルスクリーンモードはElement.requestFullscreen()メソッドで簡単に実装できます。
以下ソース。
export const toggleFullScreen = () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else if (document.exitFullscreen) {
document.exitFullscreen();
}
};
これだけ。
document.fullscreenElement
は全画面モードを使用していなければnullを返すので、全画面じゃないときにFullScreenのrequestを行うという処理。nullでないときは全画面を抜ける……と。つくってみたら非常に簡単でした。
サムネイル表示モード
いまだに綺麗に四角形で画像を切り抜く方法がわからない。とりあえず下記で対応
import { isEmpty } from 'rambda';
import { useViewerStore } from '../stores/viewerStore';
export const Thumbnail = () => {
const setPage = useViewerStore((state) => state.setPage);
const changeMode = useViewerStore((state) => state.changeMode);
const pageItems = useViewerStore((state) => state.pageItems);
return (
<div className="mx-auto bg-slate-800 text-white overflow-hidden">
{isEmpty(pageItems) ? (
<div className="h-screen w-screen"> </div>
) : (
<div className="grid grid-cols-6 gap-4">
{pageItems.map(({ url }, index) => (
<button
type="button"
onClick={() => {
changeMode('single');
setPage(index);
}}
key={url}
>
<div style={{ width: '15vmin', height: '15vmin' }}>
<img src={`${url}`} alt="" className="object-cover w-full h-full" />
</div>
</button>
))}
</div>
)}
</div>
);
};
grid, grid-cols-6, gap4で6列までのgridを生成。
あとはdivのwidth:15vmin, height:15vminで正方形にしている感じ。まだちょっと微妙な気もする。うまいこといい感じのサイズの正方形を画面に横に6個敷き詰める……ということがやりたい。
妻が来たモード(エスケープコード)
単純にeキーを押した瞬間、かわいい猫のフリー素材画像が表示されるだけの機能。緊急回避モード。これはsingleView,spreadView,thumbnailViewなどをモード切り替えで表示しているから、escapeモードに変更するだけ。
export const Viewer = () => {
const mode = useViewerStore((state) => state.mode);
return match(mode)
.with('single', () => <SingleView />)
.with('spreadStartRight', () => <SpreadStartRight />)
.with('thumbnail', () => <Thumbnail />)
.with('escape', () => <EscapeImage />)
.exhaustive();
};
特筆すべき点はないけれども、ts-patternで分岐しているところがちょっとしたポイントかも? if文、switch文では漏れが出る可能性があるかもな〜という部分については極力ts-patternで漏れがないようにしてます。まあこの規模ならべつに使わなくても良いんですけど手癖ですね。
ファイル名の表示、非表示機能
これは最初からファイル名を表示しようと思っていたら簡単だったんだけど、URLだけを取ってきていたので根本的な部分をいろいろ変更しなければならなかった。でもしっかり型を書いていたので意外と簡単に実装できた。とりあえず型を変更して、エラーが出た箇所をちょこちょこ直していけばいい。TypeScriptのそういうところが素敵だと思う。
現在のページを表示する機能
1/60みたいに何ページ中の何ページみたいなものを表示する。なんとなく終わりがわかったほうが良いかなぁ、ということで。これは簡単。
export const PageRange = () => {
const page = useViewerStore((state) => state.page);
const pageItems = useViewerStore((state) => state.pageItems);
const isShowRange = useViewerStore((state) => state.isShowRange);
return isShowRange && !isEmpty(pageItems) ? (
<div className="z-50 absolute top-0 left-0 bg-slate-400 opacity-70">
{page + 1}/{pageItems.length}
</div>
) : null;
};
そんな感じでコツコツ更新してみました。そもそもアイコンなんとかしたいとかいろいろあるんですけど、自分で使ってて不満のある部分を調整しているので後回しになってますね。
ramda.jsとかts-patternとか好きなんですが、なかなか業務では使いづらいのでここぞとばかりにいろいろ遊んでます。業務だとlodashになるんですよね。どうしても。ramdaもいいと思うけどな。