すくらっぷ あんど びるどー(したい)

日々やった事のメモとかまとめ。

スレッド型執筆アプリをGoogle Antigravityでつくった。

200字で文章をメモするのを頼んで作ってもらった。 元々情報カード的なメモをやっていて、そういったメモが欲しくて行った。またTwitterのリプライ的なのがやりやすかったのでそれを基本としている。
また200字の制限をしているのは「知的生産の技術」を元にしている。

1. 技術スタック

  • Frontend: React (Vite)
  • Styling: Vanilla CSS (CSS変数によるダークモード管理)
  • Icons: Lucide React
  • State Management: React Hooks (useState, useEffect, useRef)
  • Database: LocalStorage (ブラウザ保存による設定不要の永続化)

2. コア機能の設計

スレッド構造(ツリーデータ)の管理

/* データ構造の例 */
const memo = {
  id: "uuid-1",
  content: "メインのアイデア",
  parentId: null, // 親がいない場合は独立した投稿
  createdAt: "2024-02-25T...",
  sortOrder: 1708800000000 // 手動並べ替え用の指標
};

執筆と同時に「統合」されるプレビュー

メモだけだと文章にならないので、右のサイドバーにまとめるようにしてもらった。

// ツリーを深さ優先探索で走査して文章を結合
const getConsolidatedText = () => {
  const memoMap = new Map();
  memos.forEach(m => memoMap.set(m.id, { ...m, children: [] }));
  const roots = [];
  memos.forEach(m => {
    if (m.parentId && memoMap.has(m.parentId)) {
      memoMap.get(m.parentId).children.push(memoMap.get(m.id));
    } else {
      roots.push(memoMap.get(m.id));
    }
  });
  
  const result = [];
  const traverse = (node) => {
    result.push(node.content);
    node.children.sort((a, b) => b.sortOrder - a.sortOrder).forEach(traverse);
  };
  roots.forEach(traverse);
  return result.join('\n\n');
};

3. 実装のハイライト

インライン・リプライ UI

Twitterの体験を損なわないよう、返信ボタンを押した瞬間にその場で入力欄が開くインライン入力を設計しました。setTimeout を使い、描画直後のフォーカスを制御しています。

とのこと(無能)。

{isReplying && (
  <div className="inline-reply-container">
    <textarea
      ref={replyRef}
      autoFocus
      placeholder="返信を投稿..."
      onChange={(e) => setReplyValue(e.target.value)}
    />
    <div className="input-footer">
      <button onClick={() => addMemo(replyValue, memo.id)}>返信</button>
    </div>
  </div>
)}

実際にはTwitterにこだわる理由はあんまりない。
だがTwitterの形式がやりやすかったのは事実である。その辺があって選んでいる。

ドラッグ&ドロップ不要の簡単並べ替え

執筆中に構成を入れ替えやすくするため、各メモに「↑」「↓」ボタンを配置。配列内の sortOrder をスワップさせることで、軽量なロジックで並べ替えを実現

4. プロダクトのデザイン

三カム構成になっている。

  1. 左サイドバー (275px): ナビゲーションとプロジェクト管理
  2. 中央フィード (600px): 執筆エリア。読みやすさを考慮した本家準拠の幅。
  3. 右サイドバー (1fr): 統合プレビュー。下一杯まで広がるカード型デザイン。

完成品

5. まとめ

基本的はメモ帳である。あと正直、普通に書くだけならアウトライナーで事足りる。
じゃあなんで作ったのかと言えば、情報カード的な操作とメモをするのがしたかったのと、普通のアウトライナーであると200字制限を設定するのが難しかったからである。 この制限を付けるのが一番欲しかったまである。強制的にやることで自然とカードと同じ効果がでるからである。
とはいえまだ作ったばかりなので使用感がちょっとわからない。改造しながら使う事になると思う。