Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

4年使って作った俺的最強 Moonlander レイアウト

ここからダウンロードできます→レイアウトデータ

工夫ポイントたち

  • 日本語入力と英語入力のスイッチがある
  • 役割ごとにキーに色をつけて光らせている
  • レイヤーの切り替えがしやすい
  • 矢印キーの配置が直感的

工夫1: 日本語入力と英語入力のスイッチがある

正直この機能のためだけにmoonlanderを使ってる と言っても過言でないです。親指部分に「日本語入力に切り替える」キーと「英語入力に切り替える」キーがあります。それらを押すと一発で入力が切り替わります。このキーによって作業効率が1.5倍は上がってます。

工夫2: 役割ごとにキーに色をつけて光らせている

テンキー部分が水色に光っている

たとえばテンキーを含んだレイヤーでは、テンキーの位置が水色に光ります。 ほかの光ってるキーはライティング色を変えるキー、レイヤー切り替えキーなどです。

こういう変なレイアウトのレイヤーでは、役割のあるキーに色をつけておくと便利 です。

工夫3: レイヤーの切り替えがしやすい

カンタンにレイヤー切り替えできる&押し間違えない という配置にしたかったので、こんな感じになってます。

1. 右手側の右下のキーを押しっぱなしにして特殊レイヤーに切り替え、

2. 「レイヤー切り替えキー」を押してレイヤーを切り替える

この2ステップを誤って実行することはありません。なので、これなら押し間違えてレイヤーが切り替わることはありません。

工夫4: 矢印キーの配置が直感的

試行錯誤した末に「↑↓←→」という並びに落ち着きました。左手側は上下方向、右手側は左右方向 と分担されています。ほかにもhjklと同じ「←↓↑→」とかも試しましたが、なぜかしっくりきませんでした。

まとめ

特に日本語切り替えキーを配置する、役割ごとに色をつけるあたりは即実践できるtipsです。ぜひやってみてください。

デスク環境2025

去年のもの→デスク環境2024 - Panda Noir

デスク全景

デスク全景

有孔ボード

デスク周辺機器

  • デスク: FLEXISPOT E8B
  • キーボード: Moonlander
  • マイク: blue Yeti X
  • ウェブカメラ: Elgato Facecam
  • ディスプレイ: (new) ASUS 4Kモニター PA329CV

ディスプレイ以外は去年と同じ。あとはマジックトラックパッドを導入したくらい。

去年は 電子ペーパーカレンダー を作った。これが本当にすこぶる便利。自動で更新されるので手でカレンダーを用意する必要が一切なくなった。今後永遠にカレンダーを買わなくてよくなったと考えると、費用対効果がすごい。

電子ペーパーカレンダー

あとは 収納ボックス も導入した。これも地味ながら便利。上にモノを載せられるのが良い。

収納ボックス

ほかは有孔ボードを変更したくらい。新しく買ったほうはマグネットがくっつく。これのおかげでだいぶレイアウトの自由度が上がった。

まとめ

去年はそこまで劇的な変化はなかった。細かいところがアップデートされた感じ。今年はどうなっていくんだろうな。

Object.keysの型をより正確にしてみる

【TypeScript】Object.keys() の返り値をstring[]型でなくユニオン型の配列にしたい こちらの記事を読んでみて、「テンプレートリテラルを使えばもっと正確にできるのでは?」と思って書いてみました

おさらい: なぜObject.keysの返り値は string[] なのか?

(上記記事で詳しく説明されているので、ここでは軽いおさらいだけ書きます)

Object.keys は、オブジェクトのキーのうちstringとnumberのみを文字列に変換して返します。例えば Object.keys({'str': 'string', 0: 'number', [symbol]: 'symbol'})['str', '0'] となります。

これに対して、keyof はオブジェクトのキーを文字列に変換せずに返します。例えば keyof {'str': 'string', 0: 'number', [symbol]: 'symbol'}'str' | 0 | typeof symbol となります。

const obj = {str: 'string', 0: 'number', [symbol]: 'symbol'};
const keys = Object.keys(obj); // ['str', '0']
type Keys = keyof typeof obj; // 'str' | 0 | typeof symbol

このように、Object.keys と keyof は挙動が異なります。

より実際に近い挙動に書き換えてみる

keyofしたものからstringとnumberを抜き出して文字列に変換すれば、実際のObject.keysの挙動と近くなるはずです。

const getKeys = <T extends Record<PropertyKey, unknown>>(obj: T) => {
    return Object.keys(obj) as `${keyof T & (string | number)}`[];
};

const s = Symbol()
const obj = { 'str': 'string', 1: 'number', [s]: 'symbol' };

const keys = getKeys(obj); // ['str', '1']
type Keys = typeof keys; // 'str' | '1'

www.typescriptlang.org

だいぶ近くはなりました。ただし、これでもまだ不完全です。

enumerable: true で定義したpropertyを取得できない

Object.definePropertyでenumerable:trueを指定してプロパティを動的に追加した場合、Object.keysにはそのプロパティが表示されます。しかし、keyofのほうでは取得できません。

Object.defineProperty(obj, 'prop', {
  enumerable:true,
  value:42,
});
Object.keys(obj); // 'prop' が含まれる
type Keys = keyof typeof obj; // 'prop' が含まれる

…まあ当たり前っちゃ当たり前なんですが、完全にはObject.keysとkeyofの対応が取れないよという話でした

まとめ: 大抵のユースケースでは十分

Object.definePropertyで動的にプロパティを足したケースに対応できていないものの、ほとんどのケースにおいては上で紹介したgetKeys関数が使えます。 コーナーケースにはまらないように気をつけつつ使っていくのが良いと思います。

2024年を振り返る

去年の → 2023年を振り返る - Panda Noir

仕事、趣味、プライベートについて書くぞい。

仕事

  • 5年目。
    • 同じ会社に長く務めることになったのはちょっと意外だった。3年くらいで転職すると思ってた。
  • 2月に新チームへ移動(入社してから初)
    • それに伴い、業務内容のメインがサーバーになり、社内転職みたいな感じに (ウェブフロントもやってた)
    • DDD輪読会を始めたり、社内ボドゲ会を開いたりした
  • 登壇やテックブログ執筆は特になし
  • 転職を考え始めた

今年はほぼ社内転職みたいな感じだった。仕事の3割くらいはウェブフロントのままだったとはいえ、やっぱりメイン領域が変わった影響はデカかった。今までより余力が減って、全体感やアーキテクチャについて考えるための時間が減った。後半になってようやく余裕が出てきた感じ。

サーバーサイドはやっぱり、趣味と仕事だと規模が違いすぎてほぼ別物だった。耐障害性(fault tolerance)とか、メッセージキューとか、k8sとか、趣味の範疇じゃほぼ意識しないし。ウェブフロントは趣味でいじっていても十分勉強になるけど、サーバーは業務をこなさないと見えてこない。

記事執筆はぼちぼちだった。1本は200likesを超えたけど、それくらい。記事を書く頻度が明らか下がっている。会社のテックブログにも特に書いてない。今年はサーバー領域のキャッチアップに必死で発信どころじゃなかった。

登壇はしなきゃなとずっと思いつつ、なにも行動できなかったな…

12月になってから転職を考え始めた。周辺環境とか会社全体の感じがちょっとずつ自分とズレてきている、と感じてるので。もっと力があれば転職しなくてもと思うんだけどね。まあ急いではないから、1月あたりから動いて6月くらいに退社かなぁ。

趣味

  • 映画がメイン
    • ついに見た映画の記録数が500を超えた
    • ペースは意図的に落とした。新しく観た映画は131本だった(去年207本)。
  • 英語リスニングの練習として、ホームアローンとバック・トゥ・ザ・フューチャー(BTTF)の周回をした
    • これは趣味か…?
  • 合気道はそこそこ通ってた
    • 3月から行き始めて、7月8月は休んで、9月以降はちゃんと通うみたいな感じだった(月2回程度しか行けてなかったけども)
    • 今年で引退かなという気持ちがある
  • スプラは9月で封印した
    • 楽しいんだけど、ストレスが強すぎてこのままだと心身によくないと思って封印した。チーム戦が性に合ってないのかも。
  • 読書の量がそこそこ増えた
    • 今年は32冊読んだ(去年20冊)。
  • apple watchのおかげで運動習慣がついた
    • 9月から12月までの13週間ほど毎日なにかしら運動をしている

新規の趣味は開拓特にしてなくて、既存の趣味の強化って感じだった。インドア系の趣味ばっかだから来年は外に出ていきたい。

プライベート

  • 2月から7月まで付き合ってたが別れた
  • 泉まくらにハマり中
    • これは今年というかここ2年半くらいずっとだが
  • 脚トレを積極的にやった
  • 珈琲のハンドドリップにハマる
  • バーにハマる

恋愛とかもうしたくね〜〜って気持ちだったけど、意外と自分はえり好みするタイプなんだなというのが今年の気づき。いやもう恋愛したくねえけど。

筋トレでは、サボりにサボってた脚トレをようやくちゃんとやり始めた。下↓の動画を参考にやっているんだが、本当にきつい。後半の種目は40秒保たない。途中で5秒程度休まないと無理。まあ、これもなんだかんだ9月あたりからサボってしまっているので来年始まったらまた再開したい… (9月以降は有酸素を重点的にやってた)

youtu.be

帰省したときに父から勧められてハンドドリップを始めた。結構楽しい。豆ごとの違いとかは覚えられてない。飲み比べれば違いはわかるんだけど、覚えておけないからどれがどれだったっけ…となる。名前から味を連想できるようになりたいな。あと、ハンドドリップしているうちにインスタント珈琲や紅茶も飲むようになった。というか仕事中に飲むのはティーパックの紅茶がメインになった。ダージリンとアッサムが美味しい。

バーにも今年はちょくちょく行くようになった。いうてまだ10店もいけてないけど。美味しくて自分でも買ったのはデュワーズ12年とジャックダニエル。どっちもスーパーでも売ってるし美味い。

去年立てた目標の振り返り

  • 仕事はとりあえずチーム移動後もうまく回したい。まずは安定させるところを目標に動きたい。
    • これはどうだろう…?全然激動のままでまだ濁流に流されてる感じある。なんか、異動先のチームがあまりに違いすぎるから安定とか言ってる場合じゃなかったしな。
  • 恋愛はぼちぼちやっていきたい。
    • まあぼちぼちって感じだった。下半期がグダグダだったけど。
  • 英語のリスニングは来年こそちゃんとやりたいかもな…
    • これは意外と結構しっかりやってるな。完全に彼女が英語教師だったのがデカい。別れてから全然やらなくなったが。

来年の目標

  • 外に出る機会を増やす、アウトドアの趣味を増やす
  • 婚活ある程度推し進める
  • 転職を真面目にやる
  • アウトプットを増やす

趣味がインドアすぎるので、ちょっとアクティブになろうかな。来年は最低でも2ヶ月に1回は小旅行するようにしたい。東京近郊を来年中に制覇するくらいの勢いで移動しまくりたい…!まずは都内での散歩からかな。そこから隣の県まで足を伸ばして、1泊2日までできるようなりたい。

あとはもうさっさと婚活するかなという感じかな。再来年中に結婚しておきたいから、来年である程度は進みたい。

カジュアル面談とかを通して、意外とアウトプットしてきたものが見られてるんだなと思った年だったので、来年はアウトプット量を増やしたいな。サービス作ったりもしたい。

HTML+CSSで画面を90度回転させたい

要はtransform: rotate(90deg)すればいいんですが、単にこれをやると高さと幅が異なったり、余計な余白ができます。それを回避するために、width: 100vhheight: 100vw を設定して中央寄せしてやります。すると横画面フルスクリーンを疑似的に再現できます。

以下コード

<div id="rotated">
  <h1>90度回転したコンテンツ</h1>
  <p>このコンテンツは90度回転しています。</p>
</div>
html, body {
  margin: 0;
  padding: 0;
  overflow: hidden;
  width: 100vw;
  height: 100vh;
  /* ↓#rotatedを中央寄せする */
  display: flex;
  justify-content: center;
  align-items: center;
}

#rotated {
  /* ↓ここのwidthとheightの設定がポイント*/
  min-width: 100vh;
  min-height: 100vw;
  transform: rotate(90deg);
  transform-origin: center center;
}