lookatstudy-mobile 0.22.1 → 0.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/package.json +1 -1
  2. package/seed-course.json +15 -15
  3. package/server.cjs +309 -28
  4. package/web/assets/{CanvasStage--cO-dGou.js → CanvasStage-Ba-21anG.js} +1 -1
  5. package/web/assets/{CommandPalette-B9yujZKA.js → CommandPalette-SKnzQMcN.js} +1 -1
  6. package/web/assets/{CourseSearchPanel-C7Mz8cwp.js → CourseSearchPanel-BW3fNReR.js} +1 -1
  7. package/web/assets/{ExamView-CxgAmCWD.js → ExamView-BnH6BraN.js} +1 -1
  8. package/web/assets/{MindmapView-D2NywTY1.js → MindmapView-B4SeCLQj.js} +3 -3
  9. package/web/assets/{ReviewPanel-CLOe8uSS.js → ReviewPanel-DkGT8tNA.js} +1 -1
  10. package/web/assets/{SettingsView-Crx4fWxj.js → SettingsView-dExmRnIv.js} +3 -3
  11. package/web/assets/{VoicePanel-B9o8PTlU.js → VoicePanel-CxNeKn4V.js} +2 -7
  12. package/web/assets/{abnfDiagram-N423BO3Z-DlR3JtCi.js → abnfDiagram-N423BO3Z-B4kvB05N.js} +1 -1
  13. package/web/assets/{abnfDiagram-VCTEODGH-ODA7YWAP-Cc60_NCH.js → abnfDiagram-VCTEODGH-ODA7YWAP-B5zhG8XJ.js} +1 -1
  14. package/web/assets/{architectureDiagram-5GKGNRK7-C4PU3XN7-DxA8-TH0.js → architectureDiagram-5GKGNRK7-C4PU3XN7-ybcWxxhr.js} +1 -1
  15. package/web/assets/{architectureDiagram-T3A2C74G-b87f0Zfh.js → architectureDiagram-T3A2C74G-D5eb-etB.js} +1 -1
  16. package/web/assets/{arrow-right-B_6KkCJV.js → arrow-right-D4GV0Gpo.js} +1 -1
  17. package/web/assets/{blockDiagram-NRAW4CY4-UMJ6PMQQ-DujiZmu6.js → blockDiagram-NRAW4CY4-UMJ6PMQQ-DwEVReBp.js} +1 -1
  18. package/web/assets/{blockDiagram-VBNYF7ZC-BVvgfsGF.js → blockDiagram-VBNYF7ZC-DuM7ndnl.js} +1 -1
  19. package/web/assets/{c4Diagram-5PPSVZJV-5YSQGEVW.js → c4Diagram-5PPSVZJV-BQkRaO7S.js} +1 -1
  20. package/web/assets/{c4Diagram-UCG6FXSJ-75X3U2P3-DOEKYDP0.js → c4Diagram-UCG6FXSJ-75X3U2P3-Di1jNn7S.js} +1 -1
  21. package/web/assets/channel-KoPlHvUR.js +1 -0
  22. package/web/assets/{chunk-2GRJ4B5K-7x3UypsR.js → chunk-2GRJ4B5K-C7VAL2Yd.js} +1 -1
  23. package/web/assets/{chunk-2Q5K7J3B-5RQfakW9.js → chunk-2Q5K7J3B-Jpo34qVL.js} +1 -1
  24. package/web/assets/{chunk-5RXB4S5H-CX91mO_w.js → chunk-5RXB4S5H-CrW8aZl4.js} +1 -1
  25. package/web/assets/{chunk-5VM5RSS4-DhfIWqOK.js → chunk-5VM5RSS4-Dv4MffdC.js} +1 -1
  26. package/web/assets/{chunk-6Q2QTUOP-DyBMkImn.js → chunk-6Q2QTUOP-CI07iNTB.js} +1 -1
  27. package/web/assets/{chunk-7XDTSPCN-l_wcpmq6.js → chunk-7XDTSPCN-DsQtrF-N.js} +1 -1
  28. package/web/assets/{chunk-CTNIYPP6-Bej-ifE4.js → chunk-CTNIYPP6-CpdWBpIN.js} +1 -1
  29. package/web/assets/{chunk-CXNFBKHE-BymXgi-y.js → chunk-CXNFBKHE-BDCDRaZC.js} +1 -1
  30. package/web/assets/{chunk-GF5L2VYU-DeTnv5Qk.js → chunk-GF5L2VYU-DtpZkefy.js} +1 -1
  31. package/web/assets/{chunk-ISA7TJRJ-CFmR6SoA.js → chunk-ISA7TJRJ-C3LgQ-bA.js} +1 -1
  32. package/web/assets/{chunk-JWPE2WC7-BU-fMtWi.js → chunk-JWPE2WC7-DJM1SevB.js} +1 -1
  33. package/web/assets/{chunk-KBJHAD2P-BjlTMp1m.js → chunk-KBJHAD2P-7KeTMqC1.js} +1 -1
  34. package/web/assets/{chunk-LV3HUYFY-riE_n54k.js → chunk-LV3HUYFY-B2sGhGxz.js} +1 -1
  35. package/web/assets/{chunk-M3IUQBOH-DYx0J19K.js → chunk-M3IUQBOH-Dazbegdb.js} +1 -1
  36. package/web/assets/{chunk-NDIOYS4C-D34dHdEf.js → chunk-NDIOYS4C-Cx7mCz5-.js} +1 -1
  37. package/web/assets/{chunk-RE4WF27V-qx7CV25O.js → chunk-RE4WF27V-BNzpDJts.js} +1 -1
  38. package/web/assets/{chunk-RYQCIY6F-AqdEeieF.js → chunk-RYQCIY6F-Boq_29rU.js} +1 -1
  39. package/web/assets/{chunk-VII2H2IX-CzkbeZYY.js → chunk-VII2H2IX-kQVDZD-x.js} +1 -1
  40. package/web/assets/{chunk-X5GNSKZ3-DVqvzTCj.js → chunk-X5GNSKZ3-DT5Ja5IF.js} +1 -1
  41. package/web/assets/{chunk-XCWWM2C3-BJLKBAh0.js → chunk-XCWWM2C3-BAq7zpgL.js} +1 -1
  42. package/web/assets/{chunk-XXDRQBXY-Nz1f1JPS.js → chunk-XXDRQBXY-D3vcLngc.js} +1 -1
  43. package/web/assets/classDiagram-DTDB5LWJ-LWRDKZ5K-P8Aw4zHn.js +1 -0
  44. package/web/assets/classDiagram-JCYQIIEL-Dm2NSERp.js +1 -0
  45. package/web/assets/classDiagram-v2-JRS7N3AN-2BZHGRP2-P8Aw4zHn.js +1 -0
  46. package/web/assets/classDiagram-v2-OCEON4UE-Dm2NSERp.js +1 -0
  47. package/web/assets/{core-5AezUpt1.js → core-4d9vIKK9.js} +4 -4
  48. package/web/assets/{cose-bilkent-JH36ORCC-OB24KH3T-B46Ih9E8.js → cose-bilkent-JH36ORCC-OB24KH3T-DwFzf1xR.js} +1 -1
  49. package/web/assets/{cose-bilkent-JH36ORCC-Bwf1adzB.js → cose-bilkent-JH36ORCC-RoUdcSs7.js} +1 -1
  50. package/web/assets/{cynefin-OW5HDTMX-GVF3BKWE-DcR0n-8p.js → cynefin-OW5HDTMX-GVF3BKWE-Bdt2EF7g.js} +1 -1
  51. package/web/assets/{cynefin-VYW2F7L2-BtjjXqMe.js → cynefin-VYW2F7L2-Br1TXK2f.js} +1 -1
  52. package/web/assets/{cynefinDiagram-5FMLGOSQ-H3WIRU3N-CecBQ3WS.js → cynefinDiagram-5FMLGOSQ-H3WIRU3N-DFRlDIhn.js} +1 -1
  53. package/web/assets/{cynefinDiagram-MW4NZA55-CeLD6_7i.js → cynefinDiagram-MW4NZA55-DeqLH2Db.js} +1 -1
  54. package/web/assets/{dagre-3AP2YEHR-DCERTXHT-I_531Mm0.js → dagre-3AP2YEHR-DCERTXHT-wbCkJQSQ.js} +1 -1
  55. package/web/assets/{dagre-VZM6K2ZE-BYSfxtKs.js → dagre-VZM6K2ZE-X3laLObS.js} +1 -1
  56. package/web/assets/{diagram-7IWD3JNH-CfUUB3zT.js → diagram-7IWD3JNH-8bZxUpBi.js} +1 -1
  57. package/web/assets/{diagram-B4RE2ZJO-B4h2KVGE.js → diagram-B4RE2ZJO-CsGnKBa4.js} +1 -1
  58. package/web/assets/{diagram-LBJQPF4R-BycPUMao.js → diagram-LBJQPF4R-CxaNBwKI.js} +1 -1
  59. package/web/assets/{diagram-Q27KOJAE-nUmmLOWc.js → diagram-Q27KOJAE-CjVLD6gb.js} +1 -1
  60. package/web/assets/{diagram-S7CK7UJ4-MULGZGEL-YmP_5pu9.js → diagram-S7CK7UJ4-MULGZGEL-wKLcWkw4.js} +1 -1
  61. package/web/assets/{diagram-UB23O5K3-AbqPe_Lw.js → diagram-UB23O5K3-CUZ34yVE.js} +1 -1
  62. package/web/assets/{diagram-UQ7AKVKN-YQBY353J-CSBHhT_p.js → diagram-UQ7AKVKN-YQBY353J-B_ah6OV8.js} +1 -1
  63. package/web/assets/{diagram-VSXAHHWV-WLNH2ELY-BIWRzcG_.js → diagram-VSXAHHWV-WLNH2ELY-BhbJ7E_e.js} +1 -1
  64. package/web/assets/{diagram-VX7I27RA-XW6YQV5G-DOIsDS0u.js → diagram-VX7I27RA-XW6YQV5G-DnFEyO87.js} +1 -1
  65. package/web/assets/{diagram-Z3DM3KII-HG7RF65D-CL_RkrR1.js → diagram-Z3DM3KII-HG7RF65D-Vughovua.js} +1 -1
  66. package/web/assets/{ebnfDiagram-BXEA7PRR-CiCY0Nb_.js → ebnfDiagram-BXEA7PRR-B2ehf44X.js} +1 -1
  67. package/web/assets/{ebnfDiagram-PWID7BFC-OKY4VHYD-30_W7bxy.js → ebnfDiagram-PWID7BFC-OKY4VHYD-BjbgNq8R.js} +1 -1
  68. package/web/assets/{elk.bundled-CoJK8Y5o.js → elk.bundled-CktUbZ7z.js} +1 -1
  69. package/web/assets/{erDiagram-JOGREHBK-CiMrd6Dm.js → erDiagram-JOGREHBK-9wI_YE-7.js} +1 -1
  70. package/web/assets/{erDiagram-SSCWMZ5O-PIPKOIK7-DR-Xlax4.js → erDiagram-SSCWMZ5O-PIPKOIK7-V60k7zg6.js} +1 -1
  71. package/web/assets/{flowDiagram-A5DVABFB-2Z4AVO5R-Bm2DnZWS.js → flowDiagram-A5DVABFB-2Z4AVO5R-CJdwjvtN.js} +1 -1
  72. package/web/assets/{flowDiagram-UKHOOZJN-DlA7YU9i.js → flowDiagram-UKHOOZJN-B3XmqjMH.js} +1 -1
  73. package/web/assets/{ganttDiagram-EL5Y4UJY-JZNG7GOG-CycOiHbj.js → ganttDiagram-EL5Y4UJY-JZNG7GOG-2a6TiXM3.js} +1 -1
  74. package/web/assets/{ganttDiagram-PKOTCBZU-BT4d6R51.js → ganttDiagram-PKOTCBZU-B7B9nD6g.js} +1 -1
  75. package/web/assets/{gitGraphDiagram-DS77QQ5N-DyUz04eh.js → gitGraphDiagram-DS77QQ5N-VwKL0Ozk.js} +1 -1
  76. package/web/assets/{gitGraphDiagram-WWUBYQGX-DMWMLL3G-Cp635UIu.js → gitGraphDiagram-WWUBYQGX-DMWMLL3G-BMs5FYkE.js} +1 -1
  77. package/web/assets/{index-D619gSoN.js → index-D0FRqjBW.js} +2 -2
  78. package/web/assets/{index-ClPJ1xdX.js → index-DFryMRAp.js} +6 -6
  79. package/web/assets/{index-c6Br465X.css → index-DjoBjasB.css} +1 -1
  80. package/web/assets/{index-8JL6mw1y.js → index-DkjixD09.js} +1 -1
  81. package/web/assets/{index-BSXjRLsf.js → index-Vtc_VHiK.js} +1 -1
  82. package/web/assets/{infoDiagram-6WML65LV-rj50EKNC.js → infoDiagram-6WML65LV-CD6GNI7J.js} +1 -1
  83. package/web/assets/{infoDiagram-RXCK75RN-HANS5KVC-BHovTPxo.js → infoDiagram-RXCK75RN-HANS5KVC-k8vzCiSp.js} +1 -1
  84. package/web/assets/{ishikawaDiagram-5VMMS53U-7GCIT7WU-B0aX9dg0.js → ishikawaDiagram-5VMMS53U-7GCIT7WU-Ckl5jIU6.js} +1 -1
  85. package/web/assets/{ishikawaDiagram-WSZJBQD7-Cs68VzMS.js → ishikawaDiagram-WSZJBQD7-CEdvuK4K.js} +1 -1
  86. package/web/assets/{journeyDiagram-EYS64GPL-OAPELBT7-BaF1Okyl.js → journeyDiagram-EYS64GPL-OAPELBT7-DtCRso4h.js} +1 -1
  87. package/web/assets/{journeyDiagram-NVQOT4AX-CxamcAfg.js → journeyDiagram-NVQOT4AX-CxPjI9L-.js} +1 -1
  88. package/web/assets/{kanban-definition-27J2QSJJ-CqkEoxuc.js → kanban-definition-27J2QSJJ-DnuNCFkl.js} +1 -1
  89. package/web/assets/{kanban-definition-3QL26DDD-I7RKWQQY-KQq8LJIu.js → kanban-definition-3QL26DDD-I7RKWQQY-yNRn2nj0.js} +1 -1
  90. package/web/assets/{katex-N6JRN4PM-BRgAOu7M.js → katex-N6JRN4PM-B9dEOiMG.js} +1 -1
  91. package/web/assets/main-CGE6fm01.js +462 -0
  92. package/web/assets/{mermaid-layout-elk.core-CS6tfHSb.js → mermaid-layout-elk.core-BUAJJUsd.js} +2 -2
  93. package/web/assets/{mermaid.core-D_Bznvdr.js → mermaid.core-BD32Za4p.js} +4 -4
  94. package/web/assets/{mindmap-definition-FAOFIHXS-h9YeSHf4.js → mindmap-definition-FAOFIHXS-DX6VEGs_.js} +1 -1
  95. package/web/assets/{mindmap-definition-FBJOCRG2-KIYZG64Y-DT9Y6a9o.js → mindmap-definition-FBJOCRG2-KIYZG64Y-DYiBZnHG.js} +1 -1
  96. package/web/assets/{pegDiagram-VL7TDLO6-C--Hsstu.js → pegDiagram-VL7TDLO6-Big72xut.js} +1 -1
  97. package/web/assets/{pegDiagram-XKGWAZYB-OIP57N6J-CXtA7B8B.js → pegDiagram-XKGWAZYB-OIP57N6J-N0pgSR7W.js} +1 -1
  98. package/web/assets/{pet-BWlfq4I-.js → pet-DopPVlAf.js} +1 -1
  99. package/web/assets/{pieDiagram-7S7Q4E2Y-CVnsOokB.js → pieDiagram-7S7Q4E2Y-BLXLqOCg.js} +1 -1
  100. package/web/assets/{pieDiagram-E7YTZNPT-2UOTW327-DkYfAF2K.js → pieDiagram-E7YTZNPT-2UOTW327-BuB4rTS2.js} +1 -1
  101. package/web/assets/{quadrantDiagram-AXDQQJYC-SN3ASJJK-B3grZeFo.js → quadrantDiagram-AXDQQJYC-SN3ASJJK-4S-5LgOz.js} +1 -1
  102. package/web/assets/{quadrantDiagram-CIZ2JOQS-i1yx34JH.js → quadrantDiagram-CIZ2JOQS-BUwizsLb.js} +1 -1
  103. package/web/assets/{railroadDiagram-AXF67PYL-DJuiGlbf.js → railroadDiagram-AXF67PYL-D3qxyYSE.js} +1 -1
  104. package/web/assets/{railroadDiagram-O6MQD6OU-34742W6X-up2Y0ZV_.js → railroadDiagram-O6MQD6OU-34742W6X-CzT_bN34.js} +1 -1
  105. package/web/assets/{render-O7CIS3YK-Dn1e27o_.js → render-O7CIS3YK-DhYmSGoI.js} +7 -7
  106. package/web/assets/{requirementDiagram-EFPCY7ZU-NGAFFSMB-BI_BSQB1.js → requirementDiagram-EFPCY7ZU-NGAFFSMB-iWwnW8VG.js} +1 -1
  107. package/web/assets/{requirementDiagram-LRYGKXZP-nFTGE1MQ.js → requirementDiagram-LRYGKXZP-Cf95T2or.js} +1 -1
  108. package/web/assets/{rotate-ccw-nkiipcxH.js → rotate-ccw-natFwqj6.js} +1 -1
  109. package/web/assets/{sankeyDiagram-P5KCCOFB-3D3M4XPB-Bqf3rmL6.js → sankeyDiagram-P5KCCOFB-3D3M4XPB-CjA_LC6M.js} +1 -1
  110. package/web/assets/{sankeyDiagram-W5VNT64P-BIhgGHwI.js → sankeyDiagram-W5VNT64P-CeGCHk7F.js} +1 -1
  111. package/web/assets/{sequenceDiagram-SI44F4Z6-BASko1ED.js → sequenceDiagram-SI44F4Z6-BDsExCj2.js} +1 -1
  112. package/web/assets/{sequenceDiagram-WJ2MYXX4-Q2IOPB4R-BiNVA6gm.js → sequenceDiagram-WJ2MYXX4-Q2IOPB4R-DbWhuP8u.js} +1 -1
  113. package/web/assets/{sizeCapture-X5ZJPWSS-PSGVOMYM-TxBOTj1p.js → sizeCapture-X5ZJPWSS-PSGVOMYM-DB5JtURh.js} +1 -1
  114. package/web/assets/{sizeCapture-X5ZJPWSS-CGWs4y9a.js → sizeCapture-X5ZJPWSS-_5trx7u2.js} +1 -1
  115. package/web/assets/{stateDiagram-HBIQ2CUA-4M2S6MAN-BdhmANKG.js → stateDiagram-HBIQ2CUA-4M2S6MAN-CBEhL8_A.js} +1 -1
  116. package/web/assets/{stateDiagram-OKZ733FA-CkUDyLVf.js → stateDiagram-OKZ733FA-BPHwMfDA.js} +1 -1
  117. package/web/assets/stateDiagram-v2-4QOOHH4V-LBBLA2WV-lZeXiw9L.js +1 -0
  118. package/web/assets/stateDiagram-v2-UEYNNEHI-cH9YNExR.js +1 -0
  119. package/web/assets/{swimlanes-SLNWSIFB-CZxwkAvO.js → swimlanes-SLNWSIFB-CDgj9OM9.js} +2 -2
  120. package/web/assets/{swimlanes-XN3QIQJK-N6N2CCQ6-Zac8KNFb.js → swimlanes-XN3QIQJK-N6N2CCQ6-D3F0tmOR.js} +1 -1
  121. package/web/assets/swimlanesDiagram-ULZ7WXOC-C3faa0-8.js +8 -0
  122. package/web/assets/swimlanesDiagram-VK2B7HYN-E6N4H5SY-D5nVBF4q.js +8 -0
  123. package/web/assets/{timeline-definition-24CTP7MA-KN7RSRVM-DCu4MVvb.js → timeline-definition-24CTP7MA-KN7RSRVM-C0Ufqqk-.js} +1 -1
  124. package/web/assets/{timeline-definition-Z64GVDOM-DEFnQeMY.js → timeline-definition-Z64GVDOM-81O3UI2y.js} +1 -1
  125. package/web/assets/{vennDiagram-4TSXK5OY-AKJ7LXAN-Bi1vBY1O.js → vennDiagram-4TSXK5OY-AKJ7LXAN-Cwa7TjWJ.js} +1 -1
  126. package/web/assets/{vennDiagram-T6HMQDX7-Wls_-1IU.js → vennDiagram-T6HMQDX7-BfOTIcvk.js} +1 -1
  127. package/web/assets/{wardleyDiagram-T6FBY63Y-BSjNiv26.js → wardleyDiagram-T6FBY63Y-CYCyu4_S.js} +1 -1
  128. package/web/assets/{wardleyDiagram-VM6X3IG4-3B6A3BN5-BWtS3yVZ.js → wardleyDiagram-VM6X3IG4-3B6A3BN5-CHXrbpNv.js} +1 -1
  129. package/web/assets/{xychartDiagram-ELKLHX3M-B5qgODUp.js → xychartDiagram-ELKLHX3M-7mp6PB7p.js} +1 -1
  130. package/web/assets/{xychartDiagram-S5SC5T6Z-OBDNV6WG-j0XdC2zd.js → xychartDiagram-S5SC5T6Z-OBDNV6WG-Ch73fB_B.js} +1 -1
  131. package/web/index.html +3 -3
  132. package/web/pet.html +3 -3
  133. package/web/assets/channel-CWI530Vq.js +0 -1
  134. package/web/assets/classDiagram-DTDB5LWJ-LWRDKZ5K---3y6DiQ.js +0 -1
  135. package/web/assets/classDiagram-JCYQIIEL-CKDJ6TE8.js +0 -1
  136. package/web/assets/classDiagram-v2-JRS7N3AN-2BZHGRP2---3y6DiQ.js +0 -1
  137. package/web/assets/classDiagram-v2-OCEON4UE-CKDJ6TE8.js +0 -1
  138. package/web/assets/main-BBu4fQk-.js +0 -457
  139. package/web/assets/stateDiagram-v2-4QOOHH4V-LBBLA2WV-DLoWKuNC.js +0 -1
  140. package/web/assets/stateDiagram-v2-UEYNNEHI-C4uNy_P4.js +0 -1
  141. package/web/assets/swimlanesDiagram-ULZ7WXOC-Ch9trOTe.js +0 -8
  142. package/web/assets/swimlanesDiagram-VK2B7HYN-E6N4H5SY-DBYYfTTt.js +0 -8
  143. /package/web/assets/{index-C5s4t4ce.js → index-xynt7zMk.js} +0 -0
package/server.cjs CHANGED
@@ -62413,6 +62413,13 @@ ${standaloneImages.map((img) => `- "${img.path}" (\u63CF\u8FF0: ${img.alt})`).jo
62413
62413
  - role \u5B57\u6BB5\u662F Step 2 \u7684\u6587\u4EF6\u7C7B\u578B\uFF08original/practice\uFF09\uFF0C\u4F5C\u4E3A\u53C2\u8003\u4F46\u4E0D\u662F\u552F\u4E00\u4F9D\u636E
62414
62414
  - \u5982\u679C\u4ED3\u5E93\u76EE\u5F55\u7ED3\u6784\u5DF2\u6E05\u6670\uFF08\u5982 lessons/N-Topic/\uFF09\uFF0C\u4FDD\u7559\u539F\u6709\u7AE0\u8282\uFF0C\u4E0D\u8FC7\u5EA6\u91CD\u7EC4
62415
62415
  - \u6BCF\u4E2A section \u7ED9\u4E2D\u6587\u6807\u9898
62416
+ - **\u7AE0\u8282\u6807\u9898\u5FE0\u5B9E\u539F\u5219(2026-08-23)**:\u6587\u4EF6\u5927\u7EB2\u91CC\u7684\u6807\u9898(\u4E66\u9875\u7AE0\u540D/\u76EE\u5F55\u540D/\u6587\u4EF6 H1)\u662F\u6743\u5A01\u2014\u2014lesson \u6807\u9898\u6CBF\u7528\u5B83\u4EEC
62417
+ (\u53EF\u53BB\u6389\u5197\u4F59\u524D\u7F00),\u4E0D\u8981\u6539\u5199\u6210\u522B\u7684\u4E3B\u9898;\u539F\u4E66/\u4ED3\u5E93\u81EA\u5E26\u7F16\u53F7(Chapter N/CHAPTER XX/\u7B2CN\u56DE)\u5219\u4FDD\u7559\u539F\u7F16\u53F7\u3002
62418
+ \u539F\u4E66\u6CA1\u6709\u7F16\u53F7\u7AE0\u8282\u4F53\u7CFB\u65F6,**\u4E0D\u5F97\u53D1\u660E"\u7B2C N \u7AE0"\u5F0F\u7F16\u53F7**,section \u6309\u5185\u5BB9\u4E3B\u9898\u547D\u540D(\u5982"\u9CB8\u7C7B\u5B66\u4E0E\u6355\u9CB8\u53F2",
62419
+ \u4E0D\u662F"\u7B2C 3 \u7AE0 \u9CB8\u7C7B")\u2014\u2014\u5B66\u4E60\u8005\u8981\u9760\u6807\u9898\u56DE\u5230\u539F\u4E66\u5BF9\u5E94\u4F4D\u7F6E,\u7F16\u9020\u7684\u7F16\u53F7\u4F1A\u8BEF\u5BFC
62420
+ - **\u7F51\u9875\u6765\u6E90\u7684\u6B63\u6587\u8FB9\u754C(2026-08-23)**:\u7F51\u9875\u62BD\u53D6\u7684\u6587\u4EF6(url/arXiv/\u6587\u7AE0\u7C7B)\u5C3E\u90E8\u5E38\u6B8B\u7559\u63A8\u5E7F\u6BB5\u3001\u5173\u6CE8\u5F15\u5BFC\u3001
62421
+ \u76F8\u5173\u9605\u8BFB\u7B49\u975E\u6B63\u6587\u5185\u5BB9\u3002\u5224\u65AD"\u5C3E\u90E8\u4E00\u6BB5\u662F\u5426\u5C5E\u4E8E\u6B63\u6587"\u662F\u8BED\u4E49\u5224\u65AD,\u4EA4\u7ED9\u4F60:\u660E\u663E\u662F\u4F5C\u8005\u884C\u6587\u4E00\u90E8\u5206\u7684\u4FDD\u7559;
62422
+ \u660E\u663E\u662F\u6A21\u677F\u6216\u4E0E\u4E3B\u9898\u65E0\u5173\u7684\u63A8\u5E7F\u5C0F\u6BB5,\u4E0D\u8981\u4E3A\u5B83\u5355\u72EC\u5EFA lesson,anchor \u4E5F\u4E0D\u8981\u622A\u5230\u5B83(\u6B63\u6587\u5728\u54EA\u7ED3\u675F\u4F60\u8BF4\u4E86\u7B97)
62416
62423
  - \u4EE3\u7801\u6587\u4EF6(.py/.js/.go \u7B49): \u6559\u7A0B\u578B\u4EE3\u7801(\u5E26\u8BE6\u7EC6\u6CE8\u91CA/docstring) \u2192 study world; \u5DE5\u5177/\u811A\u672C/\u7EC3\u4E60 \u2192 practice world
62417
62424
  - \u4EE3\u7801\u6587\u4EF6\u901A\u5E38\u65E0 H2/H3 \u6807\u9898\uFF0CtotalChars \u5C31\u662F\u6587\u4EF6\u5927\u5C0F\uFF0C\u4E0D\u62C6\u5206\uFF0C\u6574\u4F53\u4E00\u4E2A lesson
62418
62425
 
@@ -244640,6 +244647,33 @@ var pptx_parser_exports = {};
244640
244647
  __export(pptx_parser_exports, {
244641
244648
  parsePptx: () => parsePptx
244642
244649
  });
244650
+ function tableToMarkdown(node) {
244651
+ const rows = /* @__PURE__ */ new Map();
244652
+ const walk = (n) => {
244653
+ if (n?.type === "cell") {
244654
+ const r = Number(n.metadata?.row ?? 0);
244655
+ const c = Number(n.metadata?.col ?? 0);
244656
+ const text3 = String(n.text ?? "").trim().replace(/\|/g, "\\|").replace(/\s+/g, " ");
244657
+ if (!rows.has(r))
244658
+ rows.set(r, []);
244659
+ rows.get(r).push({ col: c, text: text3 });
244660
+ return;
244661
+ }
244662
+ for (const ch2 of n?.children ?? [])
244663
+ walk(ch2);
244664
+ };
244665
+ walk(node);
244666
+ if (rows.size === 0)
244667
+ return "";
244668
+ if ([...rows.values()].every((cells) => cells.every((c) => !c.text)))
244669
+ return "";
244670
+ const sorted = [...rows.entries()].sort((a, b) => a[0] - b[0]).map(([, cells]) => cells.sort((a, b) => a.col - b.col));
244671
+ const width = Math.max(...sorted.map((cs) => cs.length));
244672
+ const line = (texts) => `| ${Array.from({ length: width }, (_, i) => texts[i] ?? "").join(" | ")} |`;
244673
+ const header = line(sorted[0].map((c) => c.text));
244674
+ const sep3 = `| ${Array.from({ length: width }, () => "---").join(" | ")} |`;
244675
+ return [header, sep3, ...sorted.slice(1).map((cs) => line(cs.map((c) => c.text)))].join("\n");
244676
+ }
244643
244677
  async function parsePptx(buf) {
244644
244678
  const ast = await OfficeParser.parseOffice(buf, {
244645
244679
  extractAttachments: true,
@@ -244670,6 +244704,10 @@ async function parsePptx(buf) {
244670
244704
  title = child.text;
244671
244705
  else
244672
244706
  bodyTexts.push(child.text);
244707
+ } else if (child.type === "table") {
244708
+ const md = tableToMarkdown(child);
244709
+ if (md)
244710
+ bodyTexts.push(md);
244673
244711
  } else if (child.type === "image") {
244674
244712
  const name18 = child.metadata?.attachmentName;
244675
244713
  if (name18 && attMap.has(name18) && !seenImg.has(name18)) {
@@ -485219,8 +485257,14 @@ var require_pdf_parse2 = __commonJS({
485219
485257
  // src/main/lib/pdf-text.ts
485220
485258
  var pdf_text_exports = {};
485221
485259
  __export(pdf_text_exports, {
485260
+ normalizeRadicals: () => normalizeRadicals,
485222
485261
  parsePdfText: () => parsePdfText
485223
485262
  });
485263
+ function normalizeRadicals(md) {
485264
+ if (!md)
485265
+ return md;
485266
+ return /[\u2F00-\u2FDF]/.test(md) ? md.replace(/[\u2F00-\u2FDF]/g, (c) => c.normalize("NFKC")) : md;
485267
+ }
485224
485268
  async function parsePdfText(buf) {
485225
485269
  if (!process.env.LOOKATSTUDY_NO_PDF_INSPECTOR) {
485226
485270
  try {
@@ -485228,13 +485272,13 @@ async function parsePdfText(buf) {
485228
485272
  const result = await pi.processPdfAsync(buf);
485229
485273
  const md = (result?.markdown ?? "").trim();
485230
485274
  if (md)
485231
- return md;
485275
+ return normalizeRadicals(md);
485232
485276
  } catch {
485233
485277
  }
485234
485278
  }
485235
485279
  try {
485236
485280
  const pdfParse = require_pdf_parse2();
485237
- return (await pdfParse(buf)).text.trim();
485281
+ return normalizeRadicals((await pdfParse(buf)).text.trim());
485238
485282
  } catch {
485239
485283
  return "";
485240
485284
  }
@@ -486386,7 +486430,7 @@ var init_Tokenizer = __esm({
486386
486430
  // `</xmp`
486387
486431
  };
486388
486432
  Tokenizer = class {
486389
- constructor({ xmlMode = false, decodeEntities = true }, cbs) {
486433
+ constructor({ xmlMode = false, decodeEntities: decodeEntities2 = true }, cbs) {
486390
486434
  this.cbs = cbs;
486391
486435
  this.state = State.Text;
486392
486436
  this.buffer = "";
@@ -486400,7 +486444,7 @@ var init_Tokenizer = __esm({
486400
486444
  this.currentSequence = void 0;
486401
486445
  this.sequenceIndex = 0;
486402
486446
  this.xmlMode = xmlMode;
486403
- this.decodeEntities = decodeEntities;
486447
+ this.decodeEntities = decodeEntities2;
486404
486448
  this.entityDecoder = new EntityDecoder(xmlMode ? xmlDecodeTree : htmlDecodeTree, (cp, consumed) => this.emitCodePoint(cp, consumed));
486405
486449
  }
486406
486450
  reset() {
@@ -518749,7 +518793,28 @@ function extractArticle(html, baseUrl = "") {
518749
518793
  const md = alreadyHasTitleH1 ? body : `# ${title || "\u65E0\u6807\u9898\u6587\u7AE0"}
518750
518794
 
518751
518795
  ${body}`;
518752
- return { title: title || "\u65E0\u6807\u9898\u6587\u7AE0", markdown: md };
518796
+ return { title: title || "\u65E0\u6807\u9898\u6587\u7AE0", markdown: stripTailNavigation(md) };
518797
+ }
518798
+ function stripTailNavigation(md) {
518799
+ if (!md)
518800
+ return md;
518801
+ for (const suffix of INLINE_NAV_SUFFIXES)
518802
+ md = md.split(suffix).join("");
518803
+ const lines = md.split("\n");
518804
+ let end = lines.length;
518805
+ for (let i = lines.length - 1; i >= Math.max(0, lines.length - 25); i--) {
518806
+ const ln = lines[i].trim();
518807
+ if (!ln)
518808
+ continue;
518809
+ const bare = ln.replace(/^#{1,6}\s*/, "").replace(/^[>\-*]\s*/, "");
518810
+ const isNav = NAV_TAIL_PATTERNS.some((re2) => re2.test(bare) || re2.test(ln));
518811
+ const isBareImage = /^!\[[^\]]*\]\([^)]*\)$/.test(ln) || /^\S+\.(jpeg|jpg|png|gif|webp)\)?$/i.test(ln);
518812
+ if (isNav || isBareImage)
518813
+ continue;
518814
+ end = i + 1;
518815
+ break;
518816
+ }
518817
+ return lines.slice(0, end).join("\n").trimEnd();
518753
518818
  }
518754
518819
  function htmlToMarkdown(html, opts = {}) {
518755
518820
  let { document: document2 } = parseHTML(html);
@@ -518779,7 +518844,7 @@ function htmlToMarkdown(html, opts = {}) {
518779
518844
  return "";
518780
518845
  return turndown.turndown(body).trim();
518781
518846
  }
518782
- var import_readability, import_turndown, turndown;
518847
+ var import_readability, import_turndown, turndown, NAV_TAIL_PATTERNS, INLINE_NAV_SUFFIXES;
518783
518848
  var init_html_article = __esm({
518784
518849
  "src/main/services/pure/html-article.ts"() {
518785
518850
  "use strict";
@@ -518791,6 +518856,21 @@ var init_html_article = __esm({
518791
518856
  codeBlockStyle: "fenced",
518792
518857
  bulletListMarker: "-"
518793
518858
  });
518859
+ NAV_TAIL_PATTERNS = [
518860
+ /返回\S{0,6}[,,]?\s*查看更多/,
518861
+ // 搜狐模板
518862
+ /点击进入\S{0,8}首页/,
518863
+ // 搜狐模板
518864
+ /^热门文章$/,
518865
+ // 阿里云侧栏
518866
+ /^最新文章$/,
518867
+ // 阿里云侧栏
518868
+ /^目录\s*$/,
518869
+ // 阿里云侧栏(尾部窗口内)
518870
+ /^END\b.*版权/
518871
+ // 公众号转载页模板
518872
+ ];
518873
+ INLINE_NAV_SUFFIXES = ["\u76EE\u5F55 \u70ED\u95E8\u6587\u7AE0 \u6700\u65B0\u6587\u7AE0"];
518794
518874
  }
518795
518875
  });
518796
518876
 
@@ -518798,7 +518878,9 @@ var init_html_article = __esm({
518798
518878
  var epub_parser_exports = {};
518799
518879
  __export(epub_parser_exports, {
518800
518880
  parseEpub: () => parseEpub,
518801
- parseEpubFlat: () => parseEpubFlat
518881
+ parseEpubFlat: () => parseEpubFlat,
518882
+ sanitizeEpubBody: () => sanitizeEpubBody,
518883
+ splitChaptersInBody: () => splitChaptersInBody
518802
518884
  });
518803
518885
  function tags(xml, tagName19) {
518804
518886
  const out = [];
@@ -518859,6 +518941,98 @@ function parseTocLabels(tocXml, isNcx) {
518859
518941
  function sanitizeFileName(title) {
518860
518942
  return (title || "chapter").replace(/[\\/:*?"<>|#\s]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 50) || "chapter";
518861
518943
  }
518944
+ function splitChaptersInBody(body, opts) {
518945
+ const lines = body.split("\n");
518946
+ const marks = [];
518947
+ for (let i = 0; i < lines.length; i++) {
518948
+ const ln = lines[i].trimEnd();
518949
+ if (!ln || ln.length > 60)
518950
+ continue;
518951
+ const strip = (s) => s.replace(/^#{1,3}\s*/, "");
518952
+ let m = ln.match(CH_HEADING);
518953
+ if (m) {
518954
+ marks.push({ line: i, title: strip(ln), kind: "ch", seq: 0 });
518955
+ continue;
518956
+ }
518957
+ m = ln.match(LETTER_HEADING);
518958
+ if (m) {
518959
+ marks.push({ line: i, title: strip(ln), kind: "letter", seq: 0 });
518960
+ continue;
518961
+ }
518962
+ m = ln.match(ROMAN_HEADING);
518963
+ if (m && (ln.startsWith("#") || /[—[]/.test(ln))) {
518964
+ marks.push({ line: i, title: strip(ln), kind: "roman", seq: romanValue(m[1]) });
518965
+ continue;
518966
+ }
518967
+ m = ln.match(NUM_HEADING);
518968
+ if (m && (ln.startsWith("#") || /[—[]/.test(ln))) {
518969
+ marks.push({ line: i, title: strip(ln), kind: "num", seq: parseInt(m[1], 10) });
518970
+ continue;
518971
+ }
518972
+ }
518973
+ const minHigh = opts?.minHighConf ?? 2;
518974
+ const highConf = marks.filter((mk) => mk.kind === "ch" || mk.kind === "letter");
518975
+ let splitMarks;
518976
+ if (highConf.length >= minHigh) {
518977
+ splitMarks = highConf;
518978
+ } else {
518979
+ splitMarks = [];
518980
+ for (const kind of ["roman", "num"]) {
518981
+ const seq = marks.filter((mk) => mk.kind === kind);
518982
+ const chain = [];
518983
+ let expect = 0;
518984
+ for (const mk of seq) {
518985
+ if (expect === 0) {
518986
+ if (mk.seq === 1 || mk.seq === 2) {
518987
+ chain.push(mk);
518988
+ expect = mk.seq + 1;
518989
+ }
518990
+ } else if (mk.seq === expect) {
518991
+ chain.push(mk);
518992
+ expect++;
518993
+ }
518994
+ }
518995
+ if (chain.length >= 3)
518996
+ splitMarks.push(...chain);
518997
+ }
518998
+ if (splitMarks.length < 3)
518999
+ return null;
519000
+ }
519001
+ if (splitMarks.length < 1)
519002
+ return null;
519003
+ const out = [];
519004
+ const preamble = lines.slice(0, splitMarks[0].line).join("\n").trim();
519005
+ for (let k = 0; k < splitMarks.length; k++) {
519006
+ const start = splitMarks[k].line;
519007
+ const end = k + 1 < splitMarks.length ? splitMarks[k + 1].line : lines.length;
519008
+ let content = lines.slice(start + 1, end).join("\n").trim();
519009
+ if (k === 0 && preamble && preamble.length < 800) {
519010
+ content = `${preamble}
519011
+
519012
+ ${content}`.trim();
519013
+ }
519014
+ out.push({ title: splitMarks[k].title, content });
519015
+ }
519016
+ if (preamble && preamble.length >= 800) {
519017
+ out.unshift({ title: "\u5F15\u8A00", content: preamble });
519018
+ }
519019
+ return out.filter((c) => c.content.replace(/\s/g, "").length > 0);
519020
+ }
519021
+ function sanitizeEpubBody(body) {
519022
+ let md = body;
519023
+ const lines0 = md.split("\n");
519024
+ for (let i = 0; i < lines0.length; i++) {
519025
+ const ln = lines0[i].trim();
519026
+ if (ln.length <= 100 && (/(?:THE\s+)?FULL PROJECT GUTENBERG/i.test(ln) || /END OF THE PROJECT GUTENBERG/i.test(ln) || ln === "START: FULL LICENSE" || ln === "START: THE FULL LICENSE")) {
519027
+ md = lines0.slice(0, i).join("\n");
519028
+ break;
519029
+ }
519030
+ }
519031
+ md = md.replace(/^#{1,3}\s*(?:The Project Gutenberg eBook[^*\n]*|Project Gutenberg[^*\n]*)\n[\s\S]*?\n(?:\n|$)/im, "");
519032
+ md = md.replace(/^#{1,3}[ \t]*$/gm, "");
519033
+ md = md.replace(/\\?\[?\s*_?Copyright 1[6-9]\d\d[^_\n]*_?\s*\\?]?/g, "");
519034
+ return md.trim();
519035
+ }
518862
519036
  async function parseEpub(buf) {
518863
519037
  const entries3 = unzipSync(buf);
518864
519038
  const read2 = (p) => {
@@ -518911,13 +519085,48 @@ async function parseEpub(buf) {
518911
519085
  if (!md || md.replace(/[#\s>*-]/g, "").length < 8)
518912
519086
  continue;
518913
519087
  n++;
518914
- const body = md.startsWith("# ") && md.includes("\n") ? md.slice(md.indexOf("\n") + 1).trim() : md;
519088
+ const body0 = md.startsWith("# ") && md.includes("\n") ? md.slice(md.indexOf("\n") + 1).trim() : md;
518915
519089
  const firstHeading = md.startsWith("# ") ? md.split("\n")[0].slice(2).trim() : "";
518916
- const title = tocLabels.get(opfDirKey(item.href)) || firstHeading || `\u7B2C ${n} \u7AE0`;
519090
+ const fileTitle = tocLabels.get(opfDirKey(item.href)) || firstHeading || `\u7B2C ${n} \u7AE0`;
519091
+ if (/^(contents|table of contents)$/i.test(fileTitle) && body0.replace(/\s/g, "").length < 4e3)
519092
+ continue;
519093
+ if (body0.replace(/\s/g, "").length < 1500 && /project gutenberg|copyright/i.test(body0))
519094
+ continue;
519095
+ const body = sanitizeEpubBody(body0);
519096
+ if (body.replace(/\s/g, "").length < 8)
519097
+ continue;
519098
+ const titleIsLicense = /FULL PROJECT GUTENBERG|LICENSE/i.test(fileTitle);
519099
+ const split = splitChaptersInBody(body, titleIsLicense ? { minHighConf: 1 } : void 0);
519100
+ if (split && split.length >= (titleIsLicense ? 1 : 2)) {
519101
+ for (const seg of split) {
519102
+ chapters.push({
519103
+ path: `chapters/${String(n).padStart(2, "0")}-${sanitizeFileName(seg.title)}.md`,
519104
+ title: seg.title,
519105
+ markdown: `# ${seg.title}
519106
+
519107
+ ${seg.content}`
519108
+ });
519109
+ n++;
519110
+ }
519111
+ n--;
519112
+ continue;
519113
+ }
519114
+ if (titleIsLicense) {
519115
+ if (body.replace(/\s/g, "").length > 2e3) {
519116
+ chapters.push({
519117
+ path: `chapters/${String(n).padStart(2, "0")}-appendix.md`,
519118
+ title: "\u9644\u5F55",
519119
+ markdown: `# \u9644\u5F55
519120
+
519121
+ ${body}`
519122
+ });
519123
+ }
519124
+ continue;
519125
+ }
518917
519126
  chapters.push({
518918
- path: `chapters/${String(n).padStart(2, "0")}-${sanitizeFileName(title)}.md`,
518919
- title,
518920
- markdown: `# ${title}
519127
+ path: `chapters/${String(n).padStart(2, "0")}-${sanitizeFileName(fileTitle)}.md`,
519128
+ title: fileTitle,
519129
+ markdown: `# ${fileTitle}
518921
519130
 
518922
519131
  ${body}`
518923
519132
  });
@@ -518930,13 +519139,27 @@ async function parseEpubFlat(buf) {
518930
519139
  const book = await parseEpub(buf);
518931
519140
  return book.chapters.map((c) => c.markdown.replace(/^# /gm, "## ")).join("\n\n");
518932
519141
  }
518933
- var decoder;
519142
+ var decoder, CH_HEADING, LETTER_HEADING, ROMAN_HEADING, NUM_HEADING, romanValue;
518934
519143
  var init_epub_parser = __esm({
518935
519144
  "src/main/lib/epub-parser.ts"() {
518936
519145
  "use strict";
518937
519146
  init_esm2();
518938
519147
  init_html_article();
518939
519148
  decoder = new TextDecoder("utf-8");
519149
+ CH_HEADING = /^(?:#{1,3}\s*)?(?:CHAPTER|Chapter|chap\.)\s+[IVXLC0-9]{1,7}\b[.:)]?\s*(.*)$/;
519150
+ LETTER_HEADING = /^(?:#{1,3}\s*)?(?:Letter|LETTER)\s+\d{1,3}\b[.:)]?\s*(.*)$/;
519151
+ ROMAN_HEADING = /^(?:#{1,3}\s*)?(?:[—[]\s*)?([IVXLC]{1,7})\s*[—\]]?\.?\s*$/;
519152
+ NUM_HEADING = /^(?:#{1,3}\s*)?[—[]?\s*(\d{1,3})\s*[—\]]?\.?\s*$/;
519153
+ romanValue = (s) => {
519154
+ const vals = { I: 1, V: 5, X: 10, L: 50, C: 100 };
519155
+ let v = 0;
519156
+ for (let i = 0; i < s.length; i++) {
519157
+ const cur = vals[s[i]] ?? 0;
519158
+ const next = vals[s[i + 1]] ?? 0;
519159
+ v += cur < next ? -cur : cur;
519160
+ }
519161
+ return v;
519162
+ };
518940
519163
  }
518941
519164
  });
518942
519165
 
@@ -519488,11 +519711,32 @@ var init_bilibili_wbi = __esm({
519488
519711
  });
519489
519712
 
519490
519713
  // src/main/services/pure/subtitle-parse.ts
519714
+ function decodeEntities(s) {
519715
+ return s.replace(/&([a-z]+);/gi, (m, name18) => ENTITIES[name18.toLowerCase()] ?? m).replace(/&#(\d+);/g, (m, d) => {
519716
+ try {
519717
+ return String.fromCodePoint(Number(d));
519718
+ } catch {
519719
+ return m;
519720
+ }
519721
+ });
519722
+ }
519723
+ function cjkJoin(parts) {
519724
+ let s = "";
519725
+ for (const p of parts) {
519726
+ if (!s) {
519727
+ s = p;
519728
+ continue;
519729
+ }
519730
+ const last = s[s.length - 1];
519731
+ s += CJKISH.test(last) || CJKISH.test(p[0]) ? p : ` ${p}`;
519732
+ }
519733
+ return s;
519734
+ }
519491
519735
  function parseSubtitleToText(raw) {
519492
519736
  const lines = raw.replace(/\r\n/g, "\n").split("\n");
519493
519737
  const out = [];
519738
+ const recent = [];
519494
519739
  let inNote = false;
519495
- let prev = "";
519496
519740
  for (const line of lines) {
519497
519741
  const t = line.trim();
519498
519742
  if (!t) {
@@ -519513,21 +519757,56 @@ function parseSubtitleToText(raw) {
519513
519757
  continue;
519514
519758
  if (/^(Kind:|Language:|Style:|Region:|NOTE)/i.test(t))
519515
519759
  continue;
519516
- const text3 = t.replace(/<[^>]+>/g, "").replace(/&nbsp;/g, " ").trim();
519760
+ let text3 = t.replace(/<[^>]+>/g, "").trim();
519517
519761
  if (!text3)
519518
519762
  continue;
519519
- if (text3 === prev)
519763
+ if (AUTO_MARKERS.test(text3))
519764
+ continue;
519765
+ text3 = decodeEntities(text3);
519766
+ if (recent.includes(text3))
519520
519767
  continue;
519521
- prev = text3;
519522
- out.push(text3);
519768
+ recent.push(text3);
519769
+ if (recent.length > 2)
519770
+ recent.shift();
519771
+ const spoken = text3.replace(/^>{2,}\s*/, "").trim();
519772
+ if (spoken)
519773
+ out.push(spoken);
519774
+ }
519775
+ return cjkJoin(out).replace(/\s+/g, " ").trim();
519776
+ }
519777
+ function pickSubtitleFile(names) {
519778
+ const rank = (n) => {
519779
+ const m = n.toLowerCase().match(/^sub\.(.+)\.(vtt|srt)$/);
519780
+ if (!m)
519781
+ return 99;
519782
+ const lang = m[1];
519783
+ if (lang === "zh-hans" || lang === "zh-cn" || lang.startsWith("zh-hans") || lang.startsWith("zh-cn"))
519784
+ return 0;
519785
+ if (lang === "zh" || lang.startsWith("zh"))
519786
+ return 1;
519787
+ if (lang === "en" || lang.startsWith("en"))
519788
+ return 2;
519789
+ return 3;
519790
+ };
519791
+ let best = null;
519792
+ let bestRank = 99;
519793
+ for (const n of names) {
519794
+ const r = rank(n);
519795
+ if (r < bestRank) {
519796
+ best = n;
519797
+ bestRank = r;
519798
+ }
519523
519799
  }
519524
- return out.join(" ").replace(/\s+/g, " ").trim();
519800
+ return bestRank <= 3 ? best : null;
519525
519801
  }
519526
- var CUE_TIMING;
519802
+ var CUE_TIMING, AUTO_MARKERS, ENTITIES, CJKISH;
519527
519803
  var init_subtitle_parse = __esm({
519528
519804
  "src/main/services/pure/subtitle-parse.ts"() {
519529
519805
  "use strict";
519530
519806
  CUE_TIMING = /^\d{1,2}:\d{2}(?::\d{2})?[.,]\d{3}\s*-->/;
519807
+ AUTO_MARKERS = /^\[(music|applause|laughter|laughs?|silence|inaudible|cheering|foreign|blank[_\s]?audio|music playing|noise)\]$/i;
519808
+ ENTITIES = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: " " };
519809
+ CJKISH = /[\u3000-\u303f\u4e00-\u9fff\uff00-\uffef]/;
519531
519810
  }
519532
519811
  });
519533
519812
 
@@ -519669,7 +519948,7 @@ async function fetchViaYtDlp(url2, dataDir, onProgress, signal) {
519669
519948
  "--no-warnings",
519670
519949
  url2
519671
519950
  ], signal);
519672
- const subFile = (0, import_node_fs6.readdirSync)(workDir).find((f) => /^sub\..*\.(vtt|srt)$/i.test(f));
519951
+ const subFile = pickSubtitleFile((0, import_node_fs6.readdirSync)(workDir));
519673
519952
  if (subFile) {
519674
519953
  const text3 = parseSubtitleToText((0, import_node_fs6.readFileSync)((0, import_node_path6.join)(workDir, subFile), "utf8"));
519675
519954
  if (text3.length > 50) {
@@ -555090,9 +555369,10 @@ async function handleAgentChat(win, nodeId, userMessage, locale) {
555090
555369
  onProposalCreated: (id, summary) => {
555091
555370
  win?.send("chat:proposal", id, summary, "pending");
555092
555371
  },
555093
- onError: (msg) => win?.send("chat:error", msg),
555372
+ onError: (msg) => win?.send("chat:error", msg, nodeId),
555094
555373
  // v0.2 parts 协议:把 reasoning/tool-start/tool-result/tool-error 透传给渲染层
555095
- onPart: (part) => win?.send("chat:part", part)
555374
+ // (v0.23 第二参带会话标识,旧接口用 nodeId 充当;第三参同)
555375
+ onPart: (part) => win?.send("chat:part", part, nodeId, nodeId)
555096
555376
  },
555097
555377
  controller.signal,
555098
555378
  locale
@@ -555101,7 +555381,7 @@ async function handleAgentChat(win, nodeId, userMessage, locale) {
555101
555381
  history2.push({ role: "assistant", content: reply });
555102
555382
  saveChatHistory(db, nodeId, history2);
555103
555383
  markDirty();
555104
- win?.send("chat:done", reply, {});
555384
+ win?.send("chat:done", reply, {}, nodeId);
555105
555385
  return reply;
555106
555386
  }
555107
555387
  function abortAgentChat(nodeId) {
@@ -555205,8 +555485,9 @@ ${s}` : s;
555205
555485
  onProposalCreated: (id, summary) => {
555206
555486
  win?.send("chat:proposal", id, summary, "pending");
555207
555487
  },
555208
- onError: (msg) => win?.send("chat:error", msg),
555209
- onPart: (part) => win?.send("chat:part", part)
555488
+ onError: (msg) => win?.send("chat:error", msg, threadId),
555489
+ // v0.23: part 带 threadId(渲染层按 thread 分发)+focusNodeId(地图球后台指示)
555490
+ onPart: (part) => win?.send("chat:part", part, threadId, focusNodeId)
555210
555491
  },
555211
555492
  controller.signal,
555212
555493
  locale,
@@ -555223,7 +555504,7 @@ ${s}` : s;
555223
555504
  win?.send("chat:done", reply, {
555224
555505
  userMessageId: savedUserMsg.id,
555225
555506
  assistantMessageId: savedAssistantMsg.id
555226
- });
555507
+ }, threadId);
555227
555508
  return reply;
555228
555509
  }
555229
555510
  function abortAgentChatThread(threadId) {
@@ -557897,7 +558178,7 @@ function loadSeedData() {
557897
558178
  );
557898
558179
  }
557899
558180
  var SEED_DATA = loadSeedData();
557900
- var SEED_VERSION = 12;
558181
+ var SEED_VERSION = 14;
557901
558182
  function ensureSeedCourse() {
557902
558183
  const result = applySeedData(getDb(), SEED_DATA, SEED_VERSION);
557903
558184
  if (!result.skipped)
@@ -1,4 +1,4 @@
1
- import{r,j as h}from"./index-C5s4t4ce.js";import{c as T,u as L,P as D}from"./main-BBu4fQk-.js";/**
1
+ import{r,j as h}from"./index-xynt7zMk.js";import{c as T,u as L,P as D}from"./main-CGE6fm01.js";/**
2
2
  * @license lucide-react v0.468.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{r as s,j as t}from"./index-C5s4t4ce.js";import{c as y,u as v,b as k,L as j,F as N,M as w,G as C,T as M,d as _}from"./main-BBu4fQk-.js";/**
1
+ import{r as s,j as t}from"./index-xynt7zMk.js";import{c as y,u as v,b as k,L as j,F as N,M as w,G as C,T as M,d as _}from"./main-CGE6fm01.js";/**
2
2
  * @license lucide-react v0.468.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{r as u,j as t}from"./index-C5s4t4ce.js";import{c as C,U as I,u as y,a as L,d as S,X as N,e as M,T as E,C as R}from"./main-BBu4fQk-.js";/**
1
+ import{r as u,j as t}from"./index-xynt7zMk.js";import{c as C,U as I,u as y,a as L,d as S,X as N,g as M,T as E,C as R}from"./main-CGE6fm01.js";/**
2
2
  * @license lucide-react v0.468.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{r as o,k as U,j as e,c as ie}from"./index-C5s4t4ce.js";import{c as te,u as ce,a as j,k as de,T as z,o as Y,L as V,j as oe,X as xe}from"./main-BBu4fQk-.js";import{R as G}from"./rotate-ccw-nkiipcxH.js";import{A as q}from"./arrow-right-B_6KkCJV.js";/**
1
+ import{r as o,k as U,j as e,c as ie}from"./index-xynt7zMk.js";import{c as te,u as ce,a as j,l as de,T as z,p as Y,L as V,k as oe,X as xe}from"./main-CGE6fm01.js";import{R as G}from"./rotate-ccw-natFwqj6.js";import{A as q}from"./arrow-right-D4GV0Gpo.js";/**
2
2
  * @license lucide-react v0.468.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./index-8JL6mw1y.js","./index-CU6ublfJ.js","./index-C5s4t4ce.js","./index-c6Br465X.css","./index-H1bePBGl.js","./transform-CzGDKG_M.js","./min-tv6RD-6E.js","./ordinal-Cboi1Yqb.js","./init-Gi6I4Gst.js","./colors-Cc3OSVma.js"])))=>i.map(i=>d[i]);
2
- import{u as v,_ as d,B as _}from"./main-BBu4fQk-.js";import{r as o,j as a}from"./index-C5s4t4ce.js";import{C as w}from"./CanvasStage--cO-dGou.js";function b(c){const e=[];let t=null,n=0;for(const r of c.split(`
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./index-DkjixD09.js","./index-CU6ublfJ.js","./index-xynt7zMk.js","./index-DjoBjasB.css","./index-H1bePBGl.js","./transform-CzGDKG_M.js","./min-tv6RD-6E.js","./ordinal-Cboi1Yqb.js","./init-Gi6I4Gst.js","./colors-Cc3OSVma.js"])))=>i.map(i=>d[i]);
2
+ import{u as v,_ as d,B as _}from"./main-CGE6fm01.js";import{r as o,j as a}from"./index-xynt7zMk.js";import{C as w}from"./CanvasStage-Ba-21anG.js";function b(c){const e=[];let t=null,n=0;for(const r of c.split(`
3
3
  `)){const s=/^(\s*)(`{3,}|~{3,})/.exec(r);if(t==null){if(s){t=(s[2]??"")[0]??"`",n=(s[2]??"").length,e.push(`${s[1]??""}- 代码块`);continue}e.push(r)}else new RegExp(`^\\s*\\${t==="~"?"~":"`"}{${n},}\\s*$`).test(r)&&(t=null)}return e.join(`
4
- `).replace(/!\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/<!--[\s\S]*?-->/g,"")}function E(){if(typeof document>"u")return["#58cc02","#1cb0f6","#ffc800","#a67cd8","#ff7a00"];const c=getComputedStyle(document.documentElement),e=(t,n)=>{const r=c.getPropertyValue(t).trim();return r?`rgb(${r})`:n};return[e("--brand-rgb","#58cc02"),e("--accent-rgb","#1cb0f6"),e("--gold-rgb","#ffc800"),"#a67cd8",e("--warning-rgb","#ff7a00")]}function P({markdown:c}){const e=v(),t=o.useRef(null),n=o.useRef(null),[r,s]=o.useState(!1),i=b(c);return o.useEffect(()=>{let l=!1;return(async()=>{try{const[{Transformer:p},{Markmap:g}]=await Promise.all([d(()=>import("./index-8JL6mw1y.js"),__vite__mapDeps([0,1,2,3]),import.meta.url),d(()=>import("./index-H1bePBGl.js"),__vite__mapDeps([4,1,5,6,7,8,9]),import.meta.url)]),u=t.current;if(!u||l)return;if(!n.current){const f=E();n.current=g.create(u,{autoFit:!1,duration:0,pan:!1,zoom:!1,initialExpandLevel:2,maxWidth:260,spacingVertical:10,spacingHorizontal:96,paddingX:12,color:h=>{var m;return f[(((m=h.state)==null?void 0:m.depth)??0)%f.length]??f[0]}})}const{root:x}=new p().transform(i);n.current.setData(x),n.current.fit()}catch{l||s(!0)}})(),()=>{l=!0}},[i]),r?a.jsxs("div",{className:"text-body text-ink-muted flex items-center gap-2 my-4",children:[a.jsx(_,{className:"w-4 h-4"}),e("notebook.content.render_failed")]}):a.jsx("div",{"data-testid":"mindmap-view",className:"mindmap-view h-[68vh] min-h-[420px] my-2",children:a.jsx(w,{grid:!0,testid:"mindmap-stage",children:a.jsx("div",{className:"w-[1280px] h-[760px]",children:a.jsx("svg",{ref:t,className:"w-full h-full block"})})})})}export{P as MindmapView};
4
+ `).replace(/!\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/<!--[\s\S]*?-->/g,"")}function E(){if(typeof document>"u")return["#58cc02","#1cb0f6","#ffc800","#a67cd8","#ff7a00"];const c=getComputedStyle(document.documentElement),e=(t,n)=>{const r=c.getPropertyValue(t).trim();return r?`rgb(${r})`:n};return[e("--brand-rgb","#58cc02"),e("--accent-rgb","#1cb0f6"),e("--gold-rgb","#ffc800"),"#a67cd8",e("--warning-rgb","#ff7a00")]}function P({markdown:c}){const e=v(),t=o.useRef(null),n=o.useRef(null),[r,s]=o.useState(!1),i=b(c);return o.useEffect(()=>{let l=!1;return(async()=>{try{const[{Transformer:p},{Markmap:g}]=await Promise.all([d(()=>import("./index-DkjixD09.js"),__vite__mapDeps([0,1,2,3]),import.meta.url),d(()=>import("./index-H1bePBGl.js"),__vite__mapDeps([4,1,5,6,7,8,9]),import.meta.url)]),u=t.current;if(!u||l)return;if(!n.current){const f=E();n.current=g.create(u,{autoFit:!1,duration:0,pan:!1,zoom:!1,initialExpandLevel:2,maxWidth:260,spacingVertical:10,spacingHorizontal:96,paddingX:12,color:h=>{var m;return f[(((m=h.state)==null?void 0:m.depth)??0)%f.length]??f[0]}})}const{root:x}=new p().transform(i);n.current.setData(x),n.current.fit()}catch{l||s(!0)}})(),()=>{l=!0}},[i]),r?a.jsxs("div",{className:"text-body text-ink-muted flex items-center gap-2 my-4",children:[a.jsx(_,{className:"w-4 h-4"}),e("notebook.content.render_failed")]}):a.jsx("div",{"data-testid":"mindmap-view",className:"mindmap-view h-[68vh] min-h-[420px] my-2",children:a.jsx(w,{grid:!0,testid:"mindmap-stage",children:a.jsx("div",{className:"w-[1280px] h-[760px]",children:a.jsx("svg",{ref:t,className:"w-full h-full block"})})})})}export{P as MindmapView};
@@ -1 +1 @@
1
- import{r,j as e,c as S}from"./index-C5s4t4ce.js";import{u as y,a as j,S as M}from"./main-BBu4fQk-.js";function A({tree:c,onReviewNode:d,progressMap:n}){const s=y(),[x,m]=r.useState([]),[u,f]=r.useState(!0),[l,v]=r.useState(null);r.useEffect(()=>{j.getAllSrsItems().then(t=>m(t)).catch(()=>m([])).finally(()=>f(!1))},[]);const N=r.useMemo(()=>new Map(c.map(t=>[t.id,t])),[c]),p=r.useMemo(()=>new Set(x.filter(t=>t.overdue).map(t=>t.nodeId)),[x]),i=r.useMemo(()=>{const t=c.filter(b=>{var w;const o=(w=n[b.id])==null?void 0:w.status;return b.type==="lesson"&&(o==="in_progress"||o==="mastered")}),a=new Map;for(const b of t){const o=b.parentId??"(root)";a.has(o)||a.set(o,[]),a.get(o).push(b)}return a},[c,n]),g=r.useMemo(()=>Array.from(i.values()).flat().filter(t=>p.has(t.id)).length,[i,p]),h=r.useMemo(()=>Array.from(i.values()).flat(),[i]);if(r.useEffect(()=>{if(i.size>0&&(!l||!i.has(l))){const t=i.keys().next().value;t&&v(t)}},[i,l]),u)return e.jsxs("div",{className:"text-center py-12 text-body text-ink-muted flex items-center justify-center gap-2",children:[e.jsx("span",{className:"typing-dot w-1.5 h-1.5 bg-brand rounded-full inline-block"}),s("review.loading")]});if(h.length===0)return e.jsxs("div",{className:"text-center py-16","data-testid":"review-empty",children:[e.jsx("div",{className:"text-4xl mb-3 opacity-30",children:"📖"}),e.jsx("div",{className:"text-body text-ink-muted",children:s("review.empty.title")}),e.jsx("div",{className:"text-label text-ink-faint mt-1",children:s("review.empty.desc")})]});const k=t=>{var a;return((a=N.get(t))==null?void 0:a.title)??t};return e.jsxs("div",{className:"p-5 max-w-2xl mx-auto","data-testid":"review-panel",children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsx("h2",{className:"text-title font-extrabold text-ink-strong",children:s("review.title")}),g>0&&e.jsxs("span",{className:"text-label font-bold text-review","data-testid":"review-due-count",children:[g," ",s("review.due.count")]})]}),e.jsxs("button",{onClick:()=>{const t=h[Math.floor(Math.random()*h.length)];t&&d(t.id)},"data-testid":"review-interleave",className:"btn-3d-neutral w-full py-2.5 text-body mb-5 flex items-center justify-center gap-1.5",children:[e.jsx(M,{className:"w-4 h-4"}),s("review.interleave")]}),e.jsx("div",{className:"text-label font-bold text-ink-muted mb-2",children:s("review.selectSection")}),e.jsx("div",{className:"flex flex-wrap gap-1.5 mb-4",children:Array.from(i.entries()).map(([t,a])=>e.jsxs("button",{onClick:()=>v(t),className:`px-2.5 py-1 rounded-full text-label font-bold transition-colors ${l===t?"bg-brand/15 text-brand ring-1 ring-brand/30":"bg-surface-3 text-ink-muted hover:text-ink-strong"}`,children:[k(t),e.jsxs("span",{className:"ml-1 opacity-60",children:["(",a.length,")"]})]},t))}),l&&i.has(l)&&e.jsx("div",{className:"space-y-1.5","data-testid":"review-lesson-list",children:i.get(l).map(t=>{const a=p.has(t.id);return e.jsxs("div",{className:`flex items-center justify-between gap-2 p-2.5 rounded-lg transition-colors ${a?"bg-review/8 ring-1 ring-review/20":"bg-surface-3 hover:bg-surface-3/80"}`,children:[e.jsxs("div",{className:"flex items-center gap-1.5 truncate flex-1",children:[a&&e.jsx("span",{className:"shrink-0 w-1.5 h-1.5 rounded-full bg-review"}),e.jsx("span",{className:"text-body text-ink-strong truncate",children:t.title})]}),e.jsx("button",{onClick:()=>d(t.id),"data-testid":`review-lesson-${t.id.slice(0,8)}`,className:"shrink-0 px-3 py-1 rounded-lg bg-brand/15 text-brand text-label font-bold hover:bg-brand/25 transition-colors",children:s("review.reviewLesson")})]},t.id)})})]})}function E({nodeId:c,onRated:d}){const n=y(),[s,x]=r.useState(!1),[m,u]=r.useState(!1),f=async l=>{if(!(s||m)){x(!0);try{await j.recordReview(c,l),u(!0),d==null||d(),S(l>=4?"correct":"wrong")}catch{}finally{x(!1)}}};return m?e.jsx("div",{className:"text-center text-body text-brand py-2","data-testid":"self-rated",children:n("review.selfrated")}):e.jsxs("div",{className:"border-t border-[var(--border-faint)] pt-3 mt-3","data-testid":"self-rating",children:[e.jsx("div",{className:"text-caption font-bold text-ink-muted uppercase tracking-wider mb-2 text-center",children:n("review.selfrate.title")}),e.jsxs("div",{className:"grid grid-cols-3 gap-2",children:[e.jsxs("button",{onClick:()=>f(1),disabled:s,"data-testid":"rate-again",className:"py-2 rounded-lg border border-warning/40 text-warning hover:bg-warning/10 transition-colors disabled:opacity-40 flex flex-col items-center gap-0.5",children:[e.jsx("span",{className:"text-body font-bold",children:n("review.selfrate.again")}),e.jsx("span",{className:"text-caption opacity-70",children:n("review.selfrate.again.hint")})]}),e.jsxs("button",{onClick:()=>f(4),disabled:s,"data-testid":"rate-remembered",className:"py-2 rounded-lg border border-accent/40 text-accent hover:bg-accent/10 transition-colors disabled:opacity-40 flex flex-col items-center gap-0.5",children:[e.jsx("span",{className:"text-body font-bold",children:n("review.selfrate.remembered")}),e.jsx("span",{className:"text-caption opacity-70",children:n("review.selfrate.remembered.hint")})]}),e.jsxs("button",{onClick:()=>f(5),disabled:s,"data-testid":"rate-mastered",className:"py-2 rounded-lg border border-brand/40 text-brand hover:bg-brand/10 transition-colors disabled:opacity-40 flex flex-col items-center gap-0.5",children:[e.jsx("span",{className:"text-body font-bold",children:n("review.selfrate.mastered")}),e.jsx("span",{className:"text-caption opacity-70",children:n("review.selfrate.mastered.hint")})]})]})]})}export{A as ReviewPanel,E as SelfRatingCard};
1
+ import{r,j as e,c as S}from"./index-xynt7zMk.js";import{u as y,a as j,S as M}from"./main-CGE6fm01.js";function A({tree:c,onReviewNode:d,progressMap:n}){const s=y(),[x,m]=r.useState([]),[u,f]=r.useState(!0),[l,v]=r.useState(null);r.useEffect(()=>{j.getAllSrsItems().then(t=>m(t)).catch(()=>m([])).finally(()=>f(!1))},[]);const N=r.useMemo(()=>new Map(c.map(t=>[t.id,t])),[c]),p=r.useMemo(()=>new Set(x.filter(t=>t.overdue).map(t=>t.nodeId)),[x]),i=r.useMemo(()=>{const t=c.filter(b=>{var w;const o=(w=n[b.id])==null?void 0:w.status;return b.type==="lesson"&&(o==="in_progress"||o==="mastered")}),a=new Map;for(const b of t){const o=b.parentId??"(root)";a.has(o)||a.set(o,[]),a.get(o).push(b)}return a},[c,n]),g=r.useMemo(()=>Array.from(i.values()).flat().filter(t=>p.has(t.id)).length,[i,p]),h=r.useMemo(()=>Array.from(i.values()).flat(),[i]);if(r.useEffect(()=>{if(i.size>0&&(!l||!i.has(l))){const t=i.keys().next().value;t&&v(t)}},[i,l]),u)return e.jsxs("div",{className:"text-center py-12 text-body text-ink-muted flex items-center justify-center gap-2",children:[e.jsx("span",{className:"typing-dot w-1.5 h-1.5 bg-brand rounded-full inline-block"}),s("review.loading")]});if(h.length===0)return e.jsxs("div",{className:"text-center py-16","data-testid":"review-empty",children:[e.jsx("div",{className:"text-4xl mb-3 opacity-30",children:"📖"}),e.jsx("div",{className:"text-body text-ink-muted",children:s("review.empty.title")}),e.jsx("div",{className:"text-label text-ink-faint mt-1",children:s("review.empty.desc")})]});const k=t=>{var a;return((a=N.get(t))==null?void 0:a.title)??t};return e.jsxs("div",{className:"p-5 max-w-2xl mx-auto","data-testid":"review-panel",children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsx("h2",{className:"text-title font-extrabold text-ink-strong",children:s("review.title")}),g>0&&e.jsxs("span",{className:"text-label font-bold text-review","data-testid":"review-due-count",children:[g," ",s("review.due.count")]})]}),e.jsxs("button",{onClick:()=>{const t=h[Math.floor(Math.random()*h.length)];t&&d(t.id)},"data-testid":"review-interleave",className:"btn-3d-neutral w-full py-2.5 text-body mb-5 flex items-center justify-center gap-1.5",children:[e.jsx(M,{className:"w-4 h-4"}),s("review.interleave")]}),e.jsx("div",{className:"text-label font-bold text-ink-muted mb-2",children:s("review.selectSection")}),e.jsx("div",{className:"flex flex-wrap gap-1.5 mb-4",children:Array.from(i.entries()).map(([t,a])=>e.jsxs("button",{onClick:()=>v(t),className:`px-2.5 py-1 rounded-full text-label font-bold transition-colors ${l===t?"bg-brand/15 text-brand ring-1 ring-brand/30":"bg-surface-3 text-ink-muted hover:text-ink-strong"}`,children:[k(t),e.jsxs("span",{className:"ml-1 opacity-60",children:["(",a.length,")"]})]},t))}),l&&i.has(l)&&e.jsx("div",{className:"space-y-1.5","data-testid":"review-lesson-list",children:i.get(l).map(t=>{const a=p.has(t.id);return e.jsxs("div",{className:`flex items-center justify-between gap-2 p-2.5 rounded-lg transition-colors ${a?"bg-review/8 ring-1 ring-review/20":"bg-surface-3 hover:bg-surface-3/80"}`,children:[e.jsxs("div",{className:"flex items-center gap-1.5 truncate flex-1",children:[a&&e.jsx("span",{className:"shrink-0 w-1.5 h-1.5 rounded-full bg-review"}),e.jsx("span",{className:"text-body text-ink-strong truncate",children:t.title})]}),e.jsx("button",{onClick:()=>d(t.id),"data-testid":`review-lesson-${t.id.slice(0,8)}`,className:"shrink-0 px-3 py-1 rounded-lg bg-brand/15 text-brand text-label font-bold hover:bg-brand/25 transition-colors",children:s("review.reviewLesson")})]},t.id)})})]})}function E({nodeId:c,onRated:d}){const n=y(),[s,x]=r.useState(!1),[m,u]=r.useState(!1),f=async l=>{if(!(s||m)){x(!0);try{await j.recordReview(c,l),u(!0),d==null||d(),S(l>=4?"correct":"wrong")}catch{}finally{x(!1)}}};return m?e.jsx("div",{className:"text-center text-body text-brand py-2","data-testid":"self-rated",children:n("review.selfrated")}):e.jsxs("div",{className:"border-t border-[var(--border-faint)] pt-3 mt-3","data-testid":"self-rating",children:[e.jsx("div",{className:"text-caption font-bold text-ink-muted uppercase tracking-wider mb-2 text-center",children:n("review.selfrate.title")}),e.jsxs("div",{className:"grid grid-cols-3 gap-2",children:[e.jsxs("button",{onClick:()=>f(1),disabled:s,"data-testid":"rate-again",className:"py-2 rounded-lg border border-warning/40 text-warning hover:bg-warning/10 transition-colors disabled:opacity-40 flex flex-col items-center gap-0.5",children:[e.jsx("span",{className:"text-body font-bold",children:n("review.selfrate.again")}),e.jsx("span",{className:"text-caption opacity-70",children:n("review.selfrate.again.hint")})]}),e.jsxs("button",{onClick:()=>f(4),disabled:s,"data-testid":"rate-remembered",className:"py-2 rounded-lg border border-accent/40 text-accent hover:bg-accent/10 transition-colors disabled:opacity-40 flex flex-col items-center gap-0.5",children:[e.jsx("span",{className:"text-body font-bold",children:n("review.selfrate.remembered")}),e.jsx("span",{className:"text-caption opacity-70",children:n("review.selfrate.remembered.hint")})]}),e.jsxs("button",{onClick:()=>f(5),disabled:s,"data-testid":"rate-mastered",className:"py-2 rounded-lg border border-brand/40 text-brand hover:bg-brand/10 transition-colors disabled:opacity-40 flex flex-col items-center gap-0.5",children:[e.jsx("span",{className:"text-body font-bold",children:n("review.selfrate.mastered")}),e.jsx("span",{className:"text-caption opacity-70",children:n("review.selfrate.mastered.hint")})]})]})]})}export{A as ReviewPanel,E as SelfRatingCard};