[{"data":1,"prerenderedAt":424},["ShallowReactive",2],{"content-/kindle-bookshelf-ui-improvements":3,"all-pages-for-dir":422,"og-image-/kindle-bookshelf-ui-improvements":423},{"id":4,"title":5,"body":6,"category":405,"description":406,"extension":407,"meta":408,"navigation":181,"ogImage":409,"path":410,"project_name":411,"published":412,"publishedAt":413,"seo":414,"stem":415,"tags":416,"todo":409,"unpublished":412,"updatedAt":409,"__hash__":421},"pages/2026-06/2026-06-19/kindle-bookshelf-ui-improvements.md","書棚のKindle蔵書識別と漫画フィルタを整える",{"type":7,"value":8,"toc":393},"minimark",[9,13,18,41,48,51,54,57,60,63,68,75,241,258,261,265,280,284,294,297,315,318,321,324,330,334,341,344,364,367,370,389],[10,11,12],"p",{},"書棚ページの見通しが悪くなっていた。Kindleからインポートした蔵書がどれか画面から判別できず、漫画のシリーズものが1巻ずつカードを占有して★4.5以上の棚を埋めていた。1日かけて4つの改善を順に積んだ。",[14,15,17],"h2",{"id":16},"kindle蔵書識別バッジを足す","Kindle蔵書識別バッジを足す",[10,19,20,24,25,28,29,32,33,36,37,40],{},[21,22,23],"code",{},"kindle_library"," テーブルに521件入っているうち、",[21,26,27],{},"amazon_metadata"," 側ともASINで突き合うのは467件あった。APIをASIN JOINに直して ",[21,30,31],{},"is_kindle"," と ",[21,34,35],{},"is_kindle_unlimited"," の2フラグを返すようにし、",[21,38,39],{},"shelf.vue"," のカード左下に黄色い「K」バッジを描画させた。",[10,42,43,44,47],{},"最初はWHERE句のカラム名を ",[21,45,46],{},"am."," プレフィックス付きにregexで一括書換えしようとして、置換が脆かったのでやめた。SQL本体を手で書き直したほうが速い、と気づくのに数分かかった。",[10,49,50],{},"ブラウザで開くと、Kindle蔵書249件に黄色の「K」が乗っていて、フィルタで絞り込みも効いた。",[14,52,53],{"id":53},"シリーズもの集約でカードを1つにまとめる",[10,55,56],{},"カイジ、インベスターZ、BLOODY MONDAYのように1巻〜N巻が独立カードで並ぶと、★4.5以上の棚が同じシリーズで埋まる。タイトルから巻数を除去して正規化キーを作り、N巻あるシリーズは「📚 N巻」の紫バッジ付きカード1枚に集約。クリックでモーダルを開いて全巻を順序通り並べる方針にした。",[10,58,59],{},"最初の実装ではカードを物理的にスタック表示する案を出してきたが、デザインがうるさくなるので止めて、バッジ+モーダルの形に落ち着いた。",[10,61,62],{},"開いたページではカイジ13巻、インベスターZ 20巻が正しくまとまっている。「これでよさそう」と思った直後、ユーザーから「BLOODY MONDAYとかもそうじゃないですか。なんでカイジとインベスターZだけなんですか」と差し戻された。",[64,65,67],"h3",{"id":66},"bloody-mondayのregexバグ","BLOODY MONDAYのregexバグ",[10,69,70,71,74],{},"原因を追わせると、巻数除去regexの先頭が ",[21,72,73],{},"\\s+"," になっていた。",[76,77,82],"pre",{"className":78,"code":79,"language":80,"meta":81,"style":81},"language-ts shiki shiki-themes vitesse-light vitesse-light","// 修正前: スペース必須でマッチしない\nconst stripVolume = (t: string) => t.replace(/\\s+\\d+巻$/, '')\n\n// 修正後: スペース無しでもマッチ\nconst stripVolume = (t: string) => t.replace(/\\s*\\d+巻$/, '')\n","ts","",[21,83,84,93,176,183,189],{"__ignoreMap":81},[85,86,89],"span",{"class":87,"line":88},"line",1,[85,90,92],{"class":91},"sxvE3","// 修正前: スペース必須でマッチしない\n",[85,94,96,100,104,108,111,115,118,122,125,128,131,134,137,140,144,148,152,155,157,161,165,167,170,173],{"class":87,"line":95},2,[85,97,99],{"class":98},"stQ0i","const ",[85,101,103],{"class":102},"senZ8","stripVolume",[85,105,107],{"class":106},"shFtX"," =",[85,109,110],{"class":106}," (",[85,112,114],{"class":113},"s4oTP","t",[85,116,117],{"class":106},": ",[85,119,121],{"class":120},"sSkh3","string",[85,123,124],{"class":106},")",[85,126,127],{"class":106}," =>",[85,129,130],{"class":113}," t",[85,132,133],{"class":106},".",[85,135,136],{"class":102},"replace",[85,138,139],{"class":106},"(",[85,141,143],{"class":142},"sMJiu","/",[85,145,147],{"class":146},"she3A","\\s",[85,149,151],{"class":150},"sM54T","+",[85,153,154],{"class":146},"\\d",[85,156,151],{"class":150},[85,158,160],{"class":159},"sLkVR","巻",[85,162,164],{"class":163},"sHkkW","$",[85,166,143],{"class":142},[85,168,169],{"class":106},",",[85,171,172],{"class":142}," ''",[85,174,175],{"class":106},")\n",[85,177,179],{"class":87,"line":178},3,[85,180,182],{"emptyLinePlaceholder":181},true,"\n",[85,184,186],{"class":87,"line":185},4,[85,187,188],{"class":91},"// 修正後: スペース無しでもマッチ\n",[85,190,192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222,225,227,229,231,233,235,237,239],{"class":87,"line":191},5,[85,193,99],{"class":98},[85,195,103],{"class":102},[85,197,107],{"class":106},[85,199,110],{"class":106},[85,201,114],{"class":113},[85,203,117],{"class":106},[85,205,121],{"class":120},[85,207,124],{"class":106},[85,209,127],{"class":106},[85,211,130],{"class":113},[85,213,133],{"class":106},[85,215,136],{"class":102},[85,217,139],{"class":106},[85,219,143],{"class":142},[85,221,147],{"class":146},[85,223,224],{"class":150},"*",[85,226,154],{"class":146},[85,228,151],{"class":150},[85,230,160],{"class":159},[85,232,164],{"class":163},[85,234,143],{"class":142},[85,236,169],{"class":106},[85,238,172],{"class":142},[85,240,175],{"class":106},[10,242,243,246,247,250,251,253,254,257],{},[21,244,245],{},"【極！単行本シリーズ】"," を ",[21,248,249],{},"【】"," ごと先に削った後、タイトルが「BLOODY MONDAY9巻」とスペース無しで巻数が直結する。",[21,252,73],{}," だと0文字スペースに一致しないので、巻数が残ったまま別カードとして数えられていた。",[21,255,256],{},"\\s*"," に1文字直したらBLOODY MONDAYが「📚 11巻」として集約され、★4.5以上の件数も 63 → 55 に減った。",[10,259,260],{},"regex は「最低1文字必要」と「0文字でもいい」で挙動が真逆になる典型例だった。前段で文字を削る処理を入れたら、後段のregexがその削り方に依存する。",[14,262,264],{"id":263},"漫画フィルタを初期非表示で入れる","漫画フィルタを「初期非表示」で入れる",[10,266,267,268,271,272,275,276,279],{},"ユーザーから「漫画をタグで分けられるようにしてほしい」と言われ、",[21,269,270],{},"kindle_library.tags"," の ",[21,273,274],{},"comic"," を真実として ",[21,277,278],{},"is_comic"," をAPIで返し、フロントで初期非表示にした。除外94件、表示500冊 → 406冊。★5.0が8→3件、★4.5以上が165→117件に絞られて、棚が一気に実用書中心になった。",[64,281,283],{"id":282},"紙本のチが漫画扱いされない","紙本のチ。が漫画扱いされない",[10,285,286,287,290,291,293],{},"絞り込んだ画面を見ると、チ。が★4.5以上の棚に残っていた。Pythonの ",[21,288,289],{},"kindle_library_tagger.py"," でtagsを付けているので判定漏れかと思ったが、調べたら理由は単純で、チ。は紙本でKindle Unlimited対象外、つまり ",[21,292,23],{}," に1行も入っていなかった。タグを付ける入口にすら立っていない。",[10,295,296],{},"API側の判定を二段構えに変えた:",[298,299,300,309],"ol",{},[301,302,303,305,306,308],"li",{},[21,304,270],{}," に ",[21,307,274],{}," があれば漫画扱い（既存）",[301,310,311,314],{},[21,312,313],{},"amazon_metadata.title"," のパターンマッチでも漫画扱い（追加）",[10,316,317],{},"「チ。」「進撃の巨人」など紙本だけで持っている漫画のtitle正規表現を足したら、除外件数が 94 → 102件に増えて、★4.5以上の棚から漫画が完全に消えた。残ったのは『コンピュータシステムの理論と実装』『デザインの小骨話』など実用書だけ。",[64,319,320],{"id":320},"イラスト技法書も漫画枠で除外",[10,322,323],{},"「スカートの描き方、髪の描き方、ちょっぴりHな〜、漫画の基礎デッサンも漫画枠で除外してほしい」とユーザー追加要望。漫画ではないが棚に出すと並びが乱れる類の本だ。title正規表現に描き方系・基礎デッサン系のパターンを足して除外 102 → 105件。★4.5以上から技法書が消えて、棚の意味がさらに鮮明になった。",[10,325,326,327,329],{},"漫画フィルタは「漫画かどうか」ではなく「初期表示から外したい本かどうか」のフラグに育っている。名前は ",[21,328,278],{}," のまま残しているが、実質は「棚を読書ログとして見たいときに邪魔になる本」のフラグ、と捉え直した。",[14,331,333],{"id":332},"books-一覧をkindleその他で分割","/books 一覧をKindle/その他で分割",[10,335,336,337,340],{},"最後にユーザーから「",[21,338,339],{},"/books"," の一覧でKindle取り込みとそれ以外を上下に分けたい。これからKindle蔵書を積み増していくので、直近のKindleインポートが上に並んでいる形にしたい」と依頼。",[10,342,343],{},"ページを2セクションに割った:",[345,346,347,358],"ul",{},[301,348,349,353,354,357],{},[350,351,352],"strong",{},"📱 Kindle 蔵書から取り込み",": 黄色ヘッダー、3冊、",[21,355,356],{},"createdAt"," 降順",[301,359,360,363],{},[350,361,362],{},"📕 その他（PDF / 紙書籍 OCR / Notion インポート）",": グレーヘッダー、265冊",[10,365,366],{},"Kindle側に直近インポートの『明治維新とは何だったのか』『戦略質問』『31歳でFIRE』が並んでいて、これからKindleインポートを進めるたびに上のセクションが伸びる形になった。",[14,368,369],{"id":369},"学び",[345,371,372,380,383,386],{},[301,373,374,375,32,377,379],{},"regex を二段で動かすときは、前段の削除が後段のマッチ条件にどう影響するか想像する。",[21,376,73],{},[21,378,256],{}," の1文字差で BLOODY MONDAY が落ちた",[301,381,382],{},"「漫画」というラベルは、API的には「初期表示から外したい本」のフラグに自然に拡張される。名前と中身が乖離してきたら一度立ち止まる",[301,384,385],{},"データの真実が2つ（Kindle蔵書テーブルと Amazon メタデータテーブル）あるとき、フラグはどちらに置いても漏れる。両方からORで拾うのが安全",[301,387,388],{},"「Kindleからインポートしたぞ」という事実を画面のどこかに残す。これからKindleを軸にしていく予定が決まっているなら、識別子は早めに足したほうが後の整理が効く",[390,391,392],"style",{},"html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .s4oTP, html code.shiki .s4oTP{--shiki-default:#B07D48;--shiki-dark:#B07D48}html pre.shiki code .sSkh3, html code.shiki .sSkh3{--shiki-default:#2E8F82;--shiki-dark:#2E8F82}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .she3A, html code.shiki .she3A{--shiki-default:#5A6AA6;--shiki-dark:#5A6AA6}html pre.shiki code .sM54T, html code.shiki .sM54T{--shiki-default:#2F798A;--shiki-dark:#2F798A}html pre.shiki code .sLkVR, html code.shiki .sLkVR{--shiki-default:#AB5E3F;--shiki-dark:#AB5E3F}html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":81,"searchDepth":95,"depth":95,"links":394},[395,396,399,403,404],{"id":16,"depth":95,"text":17},{"id":53,"depth":95,"text":53,"children":397},[398],{"id":66,"depth":178,"text":67},{"id":263,"depth":95,"text":264,"children":400},[401,402],{"id":282,"depth":178,"text":283},{"id":320,"depth":178,"text":320},{"id":332,"depth":95,"text":333},{"id":369,"depth":95,"text":369},"dev","shelfページにKindleバッジを追加し、シリーズもの集約と漫画フィルタで一覧の見通しをよくした。BLOODY MONDAYのregexバグ、紙本のチ。問題、イラスト技法書の扱いに寄り道した記録。","md",{},null,"/kindle-bookshelf-ui-improvements","book-knowledge-base",false,"2026-06-19T00:00:00.000Z",{"title":5,"description":406},"2026-06/2026-06-19/kindle-bookshelf-ui-improvements",[411,417,418,419,420],"Kindle","Nuxt","UI改善","regex","PX8X9D_Gcqf7PF3p-QIn2bke0I4Yr9Vnz8NeQHlMS1M",[],"https://log.eurekapu.com/og/blog/kindle-bookshelf-ui-improvements.png?v=2026-06-19T00%3A00%3A00.000Z&title=%E6%9B%B8%E6%A3%9A%E3%81%AEKindle%E8%94%B5%E6%9B%B8%E8%AD%98%E5%88%A5%E3%81%A8%E6%BC%AB%E7%94%BB%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%82%92%E6%95%B4%E3%81%88%E3%82%8B&author=Kei%20Komatsu&sig=e6b8e92c1230202d",1782176331340]