lookatstudy-mobile 0.23.0 → 0.24.0

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 (142) hide show
  1. package/package.json +1 -1
  2. package/seed-course.json +15 -15
  3. package/server.cjs +342 -22
  4. package/web/assets/{CanvasStage-Ba-21anG.js → CanvasStage-u_7YeGk1.js} +1 -1
  5. package/web/assets/{CommandPalette-SKnzQMcN.js → CommandPalette-Q5j7BQf4.js} +1 -1
  6. package/web/assets/{CourseSearchPanel-BW3fNReR.js → CourseSearchPanel-BYGHjhnk.js} +1 -1
  7. package/web/assets/{ExamView-BnH6BraN.js → ExamView-DU5X7LyZ.js} +1 -1
  8. package/web/assets/{MindmapView-B4SeCLQj.js → MindmapView-C61d4ddf.js} +3 -3
  9. package/web/assets/{ReviewPanel-DkGT8tNA.js → ReviewPanel-DoLMdlpR.js} +1 -1
  10. package/web/assets/SettingsView-CD9th6O0.js +7 -0
  11. package/web/assets/{VoicePanel-CxNeKn4V.js → VoicePanel-Cvl2BLq2.js} +1 -1
  12. package/web/assets/{abnfDiagram-N423BO3Z-B4kvB05N.js → abnfDiagram-N423BO3Z-BvTcLUtE.js} +1 -1
  13. package/web/assets/{abnfDiagram-VCTEODGH-ODA7YWAP-B5zhG8XJ.js → abnfDiagram-VCTEODGH-ODA7YWAP-NpbseUTF.js} +1 -1
  14. package/web/assets/{architectureDiagram-5GKGNRK7-C4PU3XN7-ybcWxxhr.js → architectureDiagram-5GKGNRK7-C4PU3XN7-DGtDmisd.js} +1 -1
  15. package/web/assets/{architectureDiagram-T3A2C74G-D5eb-etB.js → architectureDiagram-T3A2C74G-huu8moy9.js} +1 -1
  16. package/web/assets/{arrow-right-D4GV0Gpo.js → arrow-right-B0QrRNSR.js} +1 -1
  17. package/web/assets/{blockDiagram-NRAW4CY4-UMJ6PMQQ-DwEVReBp.js → blockDiagram-NRAW4CY4-UMJ6PMQQ-BxiaVwV9.js} +1 -1
  18. package/web/assets/{blockDiagram-VBNYF7ZC-DuM7ndnl.js → blockDiagram-VBNYF7ZC-BAnlmDNm.js} +1 -1
  19. package/web/assets/{c4Diagram-5PPSVZJV-BQkRaO7S.js → c4Diagram-5PPSVZJV-MUU8xp1X.js} +1 -1
  20. package/web/assets/{c4Diagram-UCG6FXSJ-75X3U2P3-Di1jNn7S.js → c4Diagram-UCG6FXSJ-75X3U2P3-7rpgYEob.js} +1 -1
  21. package/web/assets/channel-BJoUn5Z8.js +1 -0
  22. package/web/assets/{chunk-2GRJ4B5K-C7VAL2Yd.js → chunk-2GRJ4B5K-BZ6Sj0-3.js} +1 -1
  23. package/web/assets/{chunk-2Q5K7J3B-Jpo34qVL.js → chunk-2Q5K7J3B-BkOSQBqV.js} +1 -1
  24. package/web/assets/{chunk-5RXB4S5H-CrW8aZl4.js → chunk-5RXB4S5H-DgXJvWY0.js} +1 -1
  25. package/web/assets/{chunk-5VM5RSS4-Dv4MffdC.js → chunk-5VM5RSS4-D-BptZQ9.js} +1 -1
  26. package/web/assets/{chunk-6Q2QTUOP-CI07iNTB.js → chunk-6Q2QTUOP-DIJ0lWTD.js} +1 -1
  27. package/web/assets/{chunk-7XDTSPCN-DsQtrF-N.js → chunk-7XDTSPCN-vxuDBi1y.js} +1 -1
  28. package/web/assets/{chunk-CTNIYPP6-CpdWBpIN.js → chunk-CTNIYPP6-F5ZMIO6O.js} +1 -1
  29. package/web/assets/{chunk-CXNFBKHE-BDCDRaZC.js → chunk-CXNFBKHE-CFr1EfBh.js} +1 -1
  30. package/web/assets/{chunk-GF5L2VYU-DtpZkefy.js → chunk-GF5L2VYU-jqePwawx.js} +1 -1
  31. package/web/assets/{chunk-ISA7TJRJ-C3LgQ-bA.js → chunk-ISA7TJRJ-DiKuu0wz.js} +1 -1
  32. package/web/assets/{chunk-JWPE2WC7-DJM1SevB.js → chunk-JWPE2WC7-CLC3hqKr.js} +1 -1
  33. package/web/assets/{chunk-KBJHAD2P-7KeTMqC1.js → chunk-KBJHAD2P-DSEKcYpO.js} +1 -1
  34. package/web/assets/{chunk-LV3HUYFY-B2sGhGxz.js → chunk-LV3HUYFY-P2e0-qZ6.js} +1 -1
  35. package/web/assets/{chunk-M3IUQBOH-Dazbegdb.js → chunk-M3IUQBOH-Bdt4MjFy.js} +1 -1
  36. package/web/assets/{chunk-NDIOYS4C-Cx7mCz5-.js → chunk-NDIOYS4C-7HlPLAGd.js} +1 -1
  37. package/web/assets/{chunk-RE4WF27V-BNzpDJts.js → chunk-RE4WF27V-D4vIv_G3.js} +1 -1
  38. package/web/assets/{chunk-RYQCIY6F-Boq_29rU.js → chunk-RYQCIY6F-tTcuHeqw.js} +1 -1
  39. package/web/assets/{chunk-VII2H2IX-kQVDZD-x.js → chunk-VII2H2IX-BkXECJ1Z.js} +1 -1
  40. package/web/assets/{chunk-X5GNSKZ3-DT5Ja5IF.js → chunk-X5GNSKZ3-D7yjZGWk.js} +1 -1
  41. package/web/assets/{chunk-XCWWM2C3-BAq7zpgL.js → chunk-XCWWM2C3-C_es6n6S.js} +1 -1
  42. package/web/assets/{chunk-XXDRQBXY-D3vcLngc.js → chunk-XXDRQBXY-Bsuow-B8.js} +1 -1
  43. package/web/assets/classDiagram-DTDB5LWJ-LWRDKZ5K-B3DqqoSe.js +1 -0
  44. package/web/assets/classDiagram-JCYQIIEL-C2n-a_rM.js +1 -0
  45. package/web/assets/classDiagram-v2-JRS7N3AN-2BZHGRP2-B3DqqoSe.js +1 -0
  46. package/web/assets/classDiagram-v2-OCEON4UE-C2n-a_rM.js +1 -0
  47. package/web/assets/{core-4d9vIKK9.js → core-Bgf5ngI5.js} +1 -1
  48. package/web/assets/{cose-bilkent-JH36ORCC-OB24KH3T-DwFzf1xR.js → cose-bilkent-JH36ORCC-OB24KH3T-DM0H6Gci.js} +1 -1
  49. package/web/assets/{cose-bilkent-JH36ORCC-RoUdcSs7.js → cose-bilkent-JH36ORCC-x05QuEnY.js} +1 -1
  50. package/web/assets/{cynefin-OW5HDTMX-GVF3BKWE-Bdt2EF7g.js → cynefin-OW5HDTMX-GVF3BKWE-DY90g1OE.js} +1 -1
  51. package/web/assets/{cynefin-VYW2F7L2-Br1TXK2f.js → cynefin-VYW2F7L2-DjqH_9VW.js} +1 -1
  52. package/web/assets/{cynefinDiagram-5FMLGOSQ-H3WIRU3N-DFRlDIhn.js → cynefinDiagram-5FMLGOSQ-H3WIRU3N-DoaOZ7iJ.js} +1 -1
  53. package/web/assets/{cynefinDiagram-MW4NZA55-DeqLH2Db.js → cynefinDiagram-MW4NZA55-DI8ePik6.js} +1 -1
  54. package/web/assets/{dagre-3AP2YEHR-DCERTXHT-wbCkJQSQ.js → dagre-3AP2YEHR-DCERTXHT-BwLHkvZV.js} +1 -1
  55. package/web/assets/{dagre-VZM6K2ZE-X3laLObS.js → dagre-VZM6K2ZE-0zjstOys.js} +1 -1
  56. package/web/assets/{diagram-7IWD3JNH-8bZxUpBi.js → diagram-7IWD3JNH-CoRwcTua.js} +1 -1
  57. package/web/assets/{diagram-B4RE2ZJO-CsGnKBa4.js → diagram-B4RE2ZJO-Cau1H7nm.js} +1 -1
  58. package/web/assets/{diagram-LBJQPF4R-CxaNBwKI.js → diagram-LBJQPF4R-CZIgxCTB.js} +1 -1
  59. package/web/assets/{diagram-Q27KOJAE-CjVLD6gb.js → diagram-Q27KOJAE-B_LnuCra.js} +1 -1
  60. package/web/assets/{diagram-S7CK7UJ4-MULGZGEL-wKLcWkw4.js → diagram-S7CK7UJ4-MULGZGEL-C7lZT5bQ.js} +1 -1
  61. package/web/assets/{diagram-UB23O5K3-CUZ34yVE.js → diagram-UB23O5K3-qTFCSozX.js} +1 -1
  62. package/web/assets/{diagram-UQ7AKVKN-YQBY353J-B_ah6OV8.js → diagram-UQ7AKVKN-YQBY353J-CIootVI_.js} +1 -1
  63. package/web/assets/{diagram-VSXAHHWV-WLNH2ELY-BhbJ7E_e.js → diagram-VSXAHHWV-WLNH2ELY-BW8LpgQJ.js} +1 -1
  64. package/web/assets/{diagram-VX7I27RA-XW6YQV5G-DnFEyO87.js → diagram-VX7I27RA-XW6YQV5G-DfhGfGMR.js} +1 -1
  65. package/web/assets/{diagram-Z3DM3KII-HG7RF65D-Vughovua.js → diagram-Z3DM3KII-HG7RF65D-seunnnEY.js} +1 -1
  66. package/web/assets/{ebnfDiagram-BXEA7PRR-B2ehf44X.js → ebnfDiagram-BXEA7PRR-ksZAvx5f.js} +1 -1
  67. package/web/assets/{ebnfDiagram-PWID7BFC-OKY4VHYD-BjbgNq8R.js → ebnfDiagram-PWID7BFC-OKY4VHYD-Bvj1acAA.js} +1 -1
  68. package/web/assets/{elk.bundled-CktUbZ7z.js → elk.bundled-DP5Rghza.js} +1 -1
  69. package/web/assets/{erDiagram-JOGREHBK-9wI_YE-7.js → erDiagram-JOGREHBK-Dz3-stVV.js} +1 -1
  70. package/web/assets/{erDiagram-SSCWMZ5O-PIPKOIK7-V60k7zg6.js → erDiagram-SSCWMZ5O-PIPKOIK7-DoltPq2T.js} +1 -1
  71. package/web/assets/{flowDiagram-A5DVABFB-2Z4AVO5R-CJdwjvtN.js → flowDiagram-A5DVABFB-2Z4AVO5R-EXpUdCkE.js} +1 -1
  72. package/web/assets/{flowDiagram-UKHOOZJN-B3XmqjMH.js → flowDiagram-UKHOOZJN--KUxj2rZ.js} +1 -1
  73. package/web/assets/{ganttDiagram-EL5Y4UJY-JZNG7GOG-2a6TiXM3.js → ganttDiagram-EL5Y4UJY-JZNG7GOG-B3_qeHhv.js} +1 -1
  74. package/web/assets/{ganttDiagram-PKOTCBZU-B7B9nD6g.js → ganttDiagram-PKOTCBZU-DDw97tpG.js} +1 -1
  75. package/web/assets/{gitGraphDiagram-DS77QQ5N-VwKL0Ozk.js → gitGraphDiagram-DS77QQ5N-DXUcbzn4.js} +1 -1
  76. package/web/assets/{gitGraphDiagram-WWUBYQGX-DMWMLL3G-BMs5FYkE.js → gitGraphDiagram-WWUBYQGX-DMWMLL3G-BrLu7NzO.js} +1 -1
  77. package/web/assets/{index-DFryMRAp.js → index-BUFumkqO.js} +4 -4
  78. package/web/assets/{index-xynt7zMk.js → index-C-4sKCSr.js} +1 -1
  79. package/web/assets/{index-DkjixD09.js → index-CODVWHV0.js} +1 -1
  80. package/web/assets/{index-Vtc_VHiK.js → index-CRlVl931.js} +1 -1
  81. package/web/assets/{index-D0FRqjBW.js → index-CrB9w7Gs.js} +1 -1
  82. package/web/assets/{infoDiagram-6WML65LV-CD6GNI7J.js → infoDiagram-6WML65LV-rLhQ8DQz.js} +1 -1
  83. package/web/assets/{infoDiagram-RXCK75RN-HANS5KVC-k8vzCiSp.js → infoDiagram-RXCK75RN-HANS5KVC-BhbqgWa_.js} +1 -1
  84. package/web/assets/{ishikawaDiagram-5VMMS53U-7GCIT7WU-Ckl5jIU6.js → ishikawaDiagram-5VMMS53U-7GCIT7WU-DR-PXM0c.js} +1 -1
  85. package/web/assets/{ishikawaDiagram-WSZJBQD7-CEdvuK4K.js → ishikawaDiagram-WSZJBQD7-Bf-J9Ov1.js} +1 -1
  86. package/web/assets/{journeyDiagram-EYS64GPL-OAPELBT7-DtCRso4h.js → journeyDiagram-EYS64GPL-OAPELBT7-jFQUZit6.js} +1 -1
  87. package/web/assets/{journeyDiagram-NVQOT4AX-CxPjI9L-.js → journeyDiagram-NVQOT4AX-CWed0L5n.js} +1 -1
  88. package/web/assets/{kanban-definition-27J2QSJJ-DnuNCFkl.js → kanban-definition-27J2QSJJ-DhTIozq4.js} +1 -1
  89. package/web/assets/{kanban-definition-3QL26DDD-I7RKWQQY-yNRn2nj0.js → kanban-definition-3QL26DDD-I7RKWQQY-MOg0W8Vc.js} +1 -1
  90. package/web/assets/{katex-N6JRN4PM-B9dEOiMG.js → katex-N6JRN4PM-DUl1EV3T.js} +1 -1
  91. package/web/assets/{main-CGE6fm01.js → main-D3HpSUyK.js} +9 -9
  92. package/web/assets/{mermaid-layout-elk.core-BUAJJUsd.js → mermaid-layout-elk.core-KBAfwQxu.js} +2 -2
  93. package/web/assets/{mermaid.core-BD32Za4p.js → mermaid.core-BVbO1Vp8.js} +4 -4
  94. package/web/assets/{mindmap-definition-FAOFIHXS-DX6VEGs_.js → mindmap-definition-FAOFIHXS-UC1xDIuF.js} +1 -1
  95. package/web/assets/{mindmap-definition-FBJOCRG2-KIYZG64Y-DYiBZnHG.js → mindmap-definition-FBJOCRG2-KIYZG64Y-DyTkl7Qq.js} +1 -1
  96. package/web/assets/{pegDiagram-VL7TDLO6-Big72xut.js → pegDiagram-VL7TDLO6-D3DtO4SS.js} +1 -1
  97. package/web/assets/{pegDiagram-XKGWAZYB-OIP57N6J-N0pgSR7W.js → pegDiagram-XKGWAZYB-OIP57N6J-D6RFGa8P.js} +1 -1
  98. package/web/assets/{pet-DopPVlAf.js → pet-BawFRWlx.js} +1 -1
  99. package/web/assets/{pieDiagram-7S7Q4E2Y-BLXLqOCg.js → pieDiagram-7S7Q4E2Y-Bggk64R7.js} +1 -1
  100. package/web/assets/{pieDiagram-E7YTZNPT-2UOTW327-BuB4rTS2.js → pieDiagram-E7YTZNPT-2UOTW327-DbtP5dKZ.js} +1 -1
  101. package/web/assets/{quadrantDiagram-AXDQQJYC-SN3ASJJK-4S-5LgOz.js → quadrantDiagram-AXDQQJYC-SN3ASJJK-CbdnLdcx.js} +1 -1
  102. package/web/assets/{quadrantDiagram-CIZ2JOQS-BUwizsLb.js → quadrantDiagram-CIZ2JOQS-D8oWqljf.js} +1 -1
  103. package/web/assets/{railroadDiagram-AXF67PYL-D3qxyYSE.js → railroadDiagram-AXF67PYL-DqYMsbyG.js} +1 -1
  104. package/web/assets/{railroadDiagram-O6MQD6OU-34742W6X-CzT_bN34.js → railroadDiagram-O6MQD6OU-34742W6X-BxDZ-lKK.js} +1 -1
  105. package/web/assets/{render-O7CIS3YK-DhYmSGoI.js → render-O7CIS3YK-C5zxvpoJ.js} +7 -7
  106. package/web/assets/{requirementDiagram-EFPCY7ZU-NGAFFSMB-iWwnW8VG.js → requirementDiagram-EFPCY7ZU-NGAFFSMB-vkMFulyy.js} +1 -1
  107. package/web/assets/{requirementDiagram-LRYGKXZP-Cf95T2or.js → requirementDiagram-LRYGKXZP-4uQ-OIOg.js} +1 -1
  108. package/web/assets/{rotate-ccw-natFwqj6.js → rotate-ccw-C3k3pTDh.js} +1 -1
  109. package/web/assets/{sankeyDiagram-P5KCCOFB-3D3M4XPB-CjA_LC6M.js → sankeyDiagram-P5KCCOFB-3D3M4XPB-Ct2_9lW6.js} +1 -1
  110. package/web/assets/{sankeyDiagram-W5VNT64P-CeGCHk7F.js → sankeyDiagram-W5VNT64P-CdtMmhMM.js} +1 -1
  111. package/web/assets/{sequenceDiagram-SI44F4Z6-BDsExCj2.js → sequenceDiagram-SI44F4Z6-BTa9vGYr.js} +1 -1
  112. package/web/assets/{sequenceDiagram-WJ2MYXX4-Q2IOPB4R-DbWhuP8u.js → sequenceDiagram-WJ2MYXX4-Q2IOPB4R-Du5hMpfL.js} +1 -1
  113. package/web/assets/{sizeCapture-X5ZJPWSS-PSGVOMYM-DB5JtURh.js → sizeCapture-X5ZJPWSS-PSGVOMYM-Dv_CbP4j.js} +1 -1
  114. package/web/assets/{sizeCapture-X5ZJPWSS-_5trx7u2.js → sizeCapture-X5ZJPWSS-xJHPAAZ7.js} +1 -1
  115. package/web/assets/{stateDiagram-HBIQ2CUA-4M2S6MAN-CBEhL8_A.js → stateDiagram-HBIQ2CUA-4M2S6MAN-BhhZM57P.js} +1 -1
  116. package/web/assets/{stateDiagram-OKZ733FA-BPHwMfDA.js → stateDiagram-OKZ733FA-CHCQNs83.js} +1 -1
  117. package/web/assets/stateDiagram-v2-4QOOHH4V-LBBLA2WV-CNwPFEas.js +1 -0
  118. package/web/assets/stateDiagram-v2-UEYNNEHI-uaaN79rE.js +1 -0
  119. package/web/assets/{swimlanes-SLNWSIFB-CDgj9OM9.js → swimlanes-SLNWSIFB-Bste-JE-.js} +2 -2
  120. package/web/assets/{swimlanes-XN3QIQJK-N6N2CCQ6-D3F0tmOR.js → swimlanes-XN3QIQJK-N6N2CCQ6-03elMVxe.js} +1 -1
  121. package/web/assets/swimlanesDiagram-ULZ7WXOC-CNw-u2S_.js +8 -0
  122. package/web/assets/swimlanesDiagram-VK2B7HYN-E6N4H5SY-jhFh1EB2.js +8 -0
  123. package/web/assets/{timeline-definition-24CTP7MA-KN7RSRVM-C0Ufqqk-.js → timeline-definition-24CTP7MA-KN7RSRVM-Cba_QLsv.js} +1 -1
  124. package/web/assets/{timeline-definition-Z64GVDOM-81O3UI2y.js → timeline-definition-Z64GVDOM-nDvkF_F-.js} +1 -1
  125. package/web/assets/{vennDiagram-4TSXK5OY-AKJ7LXAN-Cwa7TjWJ.js → vennDiagram-4TSXK5OY-AKJ7LXAN-Bjm0zDVN.js} +1 -1
  126. package/web/assets/{vennDiagram-T6HMQDX7-BfOTIcvk.js → vennDiagram-T6HMQDX7-KudBxp6e.js} +1 -1
  127. package/web/assets/{wardleyDiagram-T6FBY63Y-CYCyu4_S.js → wardleyDiagram-T6FBY63Y-d1R0A5mS.js} +1 -1
  128. package/web/assets/{wardleyDiagram-VM6X3IG4-3B6A3BN5-CHXrbpNv.js → wardleyDiagram-VM6X3IG4-3B6A3BN5-BOTe--eD.js} +1 -1
  129. package/web/assets/{xychartDiagram-ELKLHX3M-7mp6PB7p.js → xychartDiagram-ELKLHX3M-ChfX530c.js} +1 -1
  130. package/web/assets/{xychartDiagram-S5SC5T6Z-OBDNV6WG-Ch73fB_B.js → xychartDiagram-S5SC5T6Z-OBDNV6WG-DcSRUgks.js} +1 -1
  131. package/web/index.html +2 -2
  132. package/web/pet.html +2 -2
  133. package/web/assets/SettingsView-dExmRnIv.js +0 -7
  134. package/web/assets/channel-KoPlHvUR.js +0 -1
  135. package/web/assets/classDiagram-DTDB5LWJ-LWRDKZ5K-P8Aw4zHn.js +0 -1
  136. package/web/assets/classDiagram-JCYQIIEL-Dm2NSERp.js +0 -1
  137. package/web/assets/classDiagram-v2-JRS7N3AN-2BZHGRP2-P8Aw4zHn.js +0 -1
  138. package/web/assets/classDiagram-v2-OCEON4UE-Dm2NSERp.js +0 -1
  139. package/web/assets/stateDiagram-v2-4QOOHH4V-LBBLA2WV-lZeXiw9L.js +0 -1
  140. package/web/assets/stateDiagram-v2-UEYNNEHI-cH9YNExR.js +0 -1
  141. package/web/assets/swimlanesDiagram-ULZ7WXOC-C3faa0-8.js +0 -8
  142. package/web/assets/swimlanesDiagram-VK2B7HYN-E6N4H5SY-D5nVBF4q.js +0 -8
package/server.cjs CHANGED
@@ -62413,6 +62413,16 @@ ${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)
62423
+ - **\u4E66\u7C4D\u7684\u524D\u7F6E/\u5916\u56F4\u5C0F\u9875(2026-08-23)**:\u7535\u5B50\u4E66\u6765\u6E90\u53EF\u80FD\u6709\u51FA\u7248\u793E\u5BA3\u4F20\u9875\u3001\u4F5C\u8005/\u8BD1\u8005\u7B80\u4ECB\u3001Digital Lab \u4E4B\u7C7B
62424
+ \u7684\u51FA\u7248\u65B9\u4ECB\u7ECD\u9875\u2014\u2014\u6807\u9898\u53EB"\u672A\u547D\u540D\u7AE0\u8282"\u7684\u6587\u4EF6\u662F\u89E3\u6790\u5C42\u8BDA\u5B9E\u6807\u6CE8"\u65E0\u6807\u9898"(\u4E0D\u662F\u539F\u4E66\u6807\u9898),\u6309\u5185\u5BB9\u4E3B\u9898\u547D\u540D\u3002
62425
+ \u660E\u663E\u4E0E\u4E66\u7684\u5185\u5BB9\u65E0\u5173\u7684\u5916\u56F4\u5C0F\u9875(\u51FA\u7248\u65B9\u4ECB\u7ECD/\u5BA3\u4F20\u8BED),\u4E0D\u8981\u4E3A\u5B83\u5355\u72EC\u5EFA lesson,\u5E76\u5165\u9996\u7AE0\u6216\u5FFD\u7565
62416
62426
  - \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
62427
  - \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
62428
 
@@ -244640,6 +244650,33 @@ var pptx_parser_exports = {};
244640
244650
  __export(pptx_parser_exports, {
244641
244651
  parsePptx: () => parsePptx
244642
244652
  });
244653
+ function tableToMarkdown(node) {
244654
+ const rows = /* @__PURE__ */ new Map();
244655
+ const walk = (n) => {
244656
+ if (n?.type === "cell") {
244657
+ const r = Number(n.metadata?.row ?? 0);
244658
+ const c = Number(n.metadata?.col ?? 0);
244659
+ const text3 = String(n.text ?? "").trim().replace(/\|/g, "\\|").replace(/\s+/g, " ");
244660
+ if (!rows.has(r))
244661
+ rows.set(r, []);
244662
+ rows.get(r).push({ col: c, text: text3 });
244663
+ return;
244664
+ }
244665
+ for (const ch2 of n?.children ?? [])
244666
+ walk(ch2);
244667
+ };
244668
+ walk(node);
244669
+ if (rows.size === 0)
244670
+ return "";
244671
+ if ([...rows.values()].every((cells) => cells.every((c) => !c.text)))
244672
+ return "";
244673
+ const sorted = [...rows.entries()].sort((a, b) => a[0] - b[0]).map(([, cells]) => cells.sort((a, b) => a.col - b.col));
244674
+ const width = Math.max(...sorted.map((cs) => cs.length));
244675
+ const line = (texts) => `| ${Array.from({ length: width }, (_, i) => texts[i] ?? "").join(" | ")} |`;
244676
+ const header = line(sorted[0].map((c) => c.text));
244677
+ const sep3 = `| ${Array.from({ length: width }, () => "---").join(" | ")} |`;
244678
+ return [header, sep3, ...sorted.slice(1).map((cs) => line(cs.map((c) => c.text)))].join("\n");
244679
+ }
244643
244680
  async function parsePptx(buf) {
244644
244681
  const ast = await OfficeParser.parseOffice(buf, {
244645
244682
  extractAttachments: true,
@@ -244670,6 +244707,10 @@ async function parsePptx(buf) {
244670
244707
  title = child.text;
244671
244708
  else
244672
244709
  bodyTexts.push(child.text);
244710
+ } else if (child.type === "table") {
244711
+ const md = tableToMarkdown(child);
244712
+ if (md)
244713
+ bodyTexts.push(md);
244673
244714
  } else if (child.type === "image") {
244674
244715
  const name18 = child.metadata?.attachmentName;
244675
244716
  if (name18 && attMap.has(name18) && !seenImg.has(name18)) {
@@ -485219,8 +485260,14 @@ var require_pdf_parse2 = __commonJS({
485219
485260
  // src/main/lib/pdf-text.ts
485220
485261
  var pdf_text_exports = {};
485221
485262
  __export(pdf_text_exports, {
485263
+ normalizeRadicals: () => normalizeRadicals,
485222
485264
  parsePdfText: () => parsePdfText
485223
485265
  });
485266
+ function normalizeRadicals(md) {
485267
+ if (!md)
485268
+ return md;
485269
+ return /[\u2F00-\u2FDF]/.test(md) ? md.replace(/[\u2F00-\u2FDF]/g, (c) => c.normalize("NFKC")) : md;
485270
+ }
485224
485271
  async function parsePdfText(buf) {
485225
485272
  if (!process.env.LOOKATSTUDY_NO_PDF_INSPECTOR) {
485226
485273
  try {
@@ -485228,13 +485275,13 @@ async function parsePdfText(buf) {
485228
485275
  const result = await pi.processPdfAsync(buf);
485229
485276
  const md = (result?.markdown ?? "").trim();
485230
485277
  if (md)
485231
- return md;
485278
+ return normalizeRadicals(md);
485232
485279
  } catch {
485233
485280
  }
485234
485281
  }
485235
485282
  try {
485236
485283
  const pdfParse = require_pdf_parse2();
485237
- return (await pdfParse(buf)).text.trim();
485284
+ return normalizeRadicals((await pdfParse(buf)).text.trim());
485238
485285
  } catch {
485239
485286
  return "";
485240
485287
  }
@@ -486386,7 +486433,7 @@ var init_Tokenizer = __esm({
486386
486433
  // `</xmp`
486387
486434
  };
486388
486435
  Tokenizer = class {
486389
- constructor({ xmlMode = false, decodeEntities = true }, cbs) {
486436
+ constructor({ xmlMode = false, decodeEntities: decodeEntities2 = true }, cbs) {
486390
486437
  this.cbs = cbs;
486391
486438
  this.state = State.Text;
486392
486439
  this.buffer = "";
@@ -486400,7 +486447,7 @@ var init_Tokenizer = __esm({
486400
486447
  this.currentSequence = void 0;
486401
486448
  this.sequenceIndex = 0;
486402
486449
  this.xmlMode = xmlMode;
486403
- this.decodeEntities = decodeEntities;
486450
+ this.decodeEntities = decodeEntities2;
486404
486451
  this.entityDecoder = new EntityDecoder(xmlMode ? xmlDecodeTree : htmlDecodeTree, (cp, consumed) => this.emitCodePoint(cp, consumed));
486405
486452
  }
486406
486453
  reset() {
@@ -518749,7 +518796,28 @@ function extractArticle(html, baseUrl = "") {
518749
518796
  const md = alreadyHasTitleH1 ? body : `# ${title || "\u65E0\u6807\u9898\u6587\u7AE0"}
518750
518797
 
518751
518798
  ${body}`;
518752
- return { title: title || "\u65E0\u6807\u9898\u6587\u7AE0", markdown: md };
518799
+ return { title: title || "\u65E0\u6807\u9898\u6587\u7AE0", markdown: stripTailNavigation(md) };
518800
+ }
518801
+ function stripTailNavigation(md) {
518802
+ if (!md)
518803
+ return md;
518804
+ for (const suffix of INLINE_NAV_SUFFIXES)
518805
+ md = md.split(suffix).join("");
518806
+ const lines = md.split("\n");
518807
+ let end = lines.length;
518808
+ for (let i = lines.length - 1; i >= Math.max(0, lines.length - 25); i--) {
518809
+ const ln = lines[i].trim();
518810
+ if (!ln)
518811
+ continue;
518812
+ const bare = ln.replace(/^#{1,6}\s*/, "").replace(/^[>\-*]\s*/, "");
518813
+ const isNav = NAV_TAIL_PATTERNS.some((re2) => re2.test(bare) || re2.test(ln));
518814
+ const isBareImage = /^!\[[^\]]*\]\([^)]*\)$/.test(ln) || /^\S+\.(jpeg|jpg|png|gif|webp)\)?$/i.test(ln);
518815
+ if (isNav || isBareImage)
518816
+ continue;
518817
+ end = i + 1;
518818
+ break;
518819
+ }
518820
+ return lines.slice(0, end).join("\n").trimEnd();
518753
518821
  }
518754
518822
  function htmlToMarkdown(html, opts = {}) {
518755
518823
  let { document: document2 } = parseHTML(html);
@@ -518779,7 +518847,7 @@ function htmlToMarkdown(html, opts = {}) {
518779
518847
  return "";
518780
518848
  return turndown.turndown(body).trim();
518781
518849
  }
518782
- var import_readability, import_turndown, turndown;
518850
+ var import_readability, import_turndown, turndown, NAV_TAIL_PATTERNS, INLINE_NAV_SUFFIXES;
518783
518851
  var init_html_article = __esm({
518784
518852
  "src/main/services/pure/html-article.ts"() {
518785
518853
  "use strict";
@@ -518791,6 +518859,21 @@ var init_html_article = __esm({
518791
518859
  codeBlockStyle: "fenced",
518792
518860
  bulletListMarker: "-"
518793
518861
  });
518862
+ NAV_TAIL_PATTERNS = [
518863
+ /返回\S{0,6}[,,]?\s*查看更多/,
518864
+ // 搜狐模板
518865
+ /点击进入\S{0,8}首页/,
518866
+ // 搜狐模板
518867
+ /^热门文章$/,
518868
+ // 阿里云侧栏
518869
+ /^最新文章$/,
518870
+ // 阿里云侧栏
518871
+ /^目录\s*$/,
518872
+ // 阿里云侧栏(尾部窗口内)
518873
+ /^END\b.*版权/
518874
+ // 公众号转载页模板
518875
+ ];
518876
+ INLINE_NAV_SUFFIXES = ["\u76EE\u5F55 \u70ED\u95E8\u6587\u7AE0 \u6700\u65B0\u6587\u7AE0"];
518794
518877
  }
518795
518878
  });
518796
518879
 
@@ -518798,7 +518881,9 @@ var init_html_article = __esm({
518798
518881
  var epub_parser_exports = {};
518799
518882
  __export(epub_parser_exports, {
518800
518883
  parseEpub: () => parseEpub,
518801
- parseEpubFlat: () => parseEpubFlat
518884
+ parseEpubFlat: () => parseEpubFlat,
518885
+ sanitizeEpubBody: () => sanitizeEpubBody,
518886
+ splitChaptersInBody: () => splitChaptersInBody
518802
518887
  });
518803
518888
  function tags(xml, tagName19) {
518804
518889
  const out = [];
@@ -518859,6 +518944,98 @@ function parseTocLabels(tocXml, isNcx) {
518859
518944
  function sanitizeFileName(title) {
518860
518945
  return (title || "chapter").replace(/[\\/:*?"<>|#\s]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 50) || "chapter";
518861
518946
  }
518947
+ function splitChaptersInBody(body, opts) {
518948
+ const lines = body.split("\n");
518949
+ const marks = [];
518950
+ for (let i = 0; i < lines.length; i++) {
518951
+ const ln = lines[i].trimEnd();
518952
+ if (!ln || ln.length > 60)
518953
+ continue;
518954
+ const strip = (s) => s.replace(/^#{1,3}\s*/, "");
518955
+ let m = ln.match(CH_HEADING);
518956
+ if (m) {
518957
+ marks.push({ line: i, title: strip(ln), kind: "ch", seq: 0 });
518958
+ continue;
518959
+ }
518960
+ m = ln.match(LETTER_HEADING);
518961
+ if (m) {
518962
+ marks.push({ line: i, title: strip(ln), kind: "letter", seq: 0 });
518963
+ continue;
518964
+ }
518965
+ m = ln.match(ROMAN_HEADING);
518966
+ if (m && (ln.startsWith("#") || /[—[]/.test(ln))) {
518967
+ marks.push({ line: i, title: strip(ln), kind: "roman", seq: romanValue(m[1]) });
518968
+ continue;
518969
+ }
518970
+ m = ln.match(NUM_HEADING);
518971
+ if (m && (ln.startsWith("#") || /[—[]/.test(ln))) {
518972
+ marks.push({ line: i, title: strip(ln), kind: "num", seq: parseInt(m[1], 10) });
518973
+ continue;
518974
+ }
518975
+ }
518976
+ const minHigh = opts?.minHighConf ?? 2;
518977
+ const highConf = marks.filter((mk) => mk.kind === "ch" || mk.kind === "letter");
518978
+ let splitMarks;
518979
+ if (highConf.length >= minHigh) {
518980
+ splitMarks = highConf;
518981
+ } else {
518982
+ splitMarks = [];
518983
+ for (const kind of ["roman", "num"]) {
518984
+ const seq = marks.filter((mk) => mk.kind === kind);
518985
+ const chain = [];
518986
+ let expect = 0;
518987
+ for (const mk of seq) {
518988
+ if (expect === 0) {
518989
+ if (mk.seq === 1 || mk.seq === 2) {
518990
+ chain.push(mk);
518991
+ expect = mk.seq + 1;
518992
+ }
518993
+ } else if (mk.seq === expect) {
518994
+ chain.push(mk);
518995
+ expect++;
518996
+ }
518997
+ }
518998
+ if (chain.length >= 3)
518999
+ splitMarks.push(...chain);
519000
+ }
519001
+ if (splitMarks.length < 3)
519002
+ return null;
519003
+ }
519004
+ if (splitMarks.length < 1)
519005
+ return null;
519006
+ const out = [];
519007
+ const preamble = lines.slice(0, splitMarks[0].line).join("\n").trim();
519008
+ for (let k = 0; k < splitMarks.length; k++) {
519009
+ const start = splitMarks[k].line;
519010
+ const end = k + 1 < splitMarks.length ? splitMarks[k + 1].line : lines.length;
519011
+ let content = lines.slice(start + 1, end).join("\n").trim();
519012
+ if (k === 0 && preamble && preamble.length < 800) {
519013
+ content = `${preamble}
519014
+
519015
+ ${content}`.trim();
519016
+ }
519017
+ out.push({ title: splitMarks[k].title, content });
519018
+ }
519019
+ if (preamble && preamble.length >= 800) {
519020
+ out.unshift({ title: "\u5F15\u8A00", content: preamble });
519021
+ }
519022
+ return out.filter((c) => c.content.replace(/\s/g, "").length > 0);
519023
+ }
519024
+ function sanitizeEpubBody(body) {
519025
+ let md = body;
519026
+ const lines0 = md.split("\n");
519027
+ for (let i = 0; i < lines0.length; i++) {
519028
+ const ln = lines0[i].trim();
519029
+ 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")) {
519030
+ md = lines0.slice(0, i).join("\n");
519031
+ break;
519032
+ }
519033
+ }
519034
+ md = md.replace(/^#{1,3}\s*(?:The Project Gutenberg eBook[^*\n]*|Project Gutenberg[^*\n]*)\n[\s\S]*?\n(?:\n|$)/im, "");
519035
+ md = md.replace(/^#{1,3}[ \t]*$/gm, "");
519036
+ md = md.replace(/\\?\[?\s*_?Copyright 1[6-9]\d\d[^_\n]*_?\s*\\?]?/g, "");
519037
+ return md.trim();
519038
+ }
518862
519039
  async function parseEpub(buf) {
518863
519040
  const entries3 = unzipSync(buf);
518864
519041
  const read2 = (p) => {
@@ -518891,6 +519068,7 @@ async function parseEpub(buf) {
518891
519068
  if (tocLabels.size === 0 && spineTocId && manifest.has(spineTocId)) {
518892
519069
  tocLabels = parseTocLabels(read2(resolveZipPath(opfPath, manifest.get(spineTocId).href)), true);
518893
519070
  }
519071
+ const UNTITLED_MARK = "\u672A\u547D\u540D\u7AE0\u8282";
518894
519072
  const opfDirKey = (href) => decodeURIComponent(href.split("#")[0] ?? href).replace(/\\/g, "/");
518895
519073
  const chapters = [];
518896
519074
  let n = 0;
@@ -518911,17 +519089,89 @@ async function parseEpub(buf) {
518911
519089
  if (!md || md.replace(/[#\s>*-]/g, "").length < 8)
518912
519090
  continue;
518913
519091
  n++;
518914
- const body = md.startsWith("# ") && md.includes("\n") ? md.slice(md.indexOf("\n") + 1).trim() : md;
519092
+ const body0 = md.startsWith("# ") && md.includes("\n") ? md.slice(md.indexOf("\n") + 1).trim() : md;
518915
519093
  const firstHeading = md.startsWith("# ") ? md.split("\n")[0].slice(2).trim() : "";
518916
- const title = tocLabels.get(opfDirKey(item.href)) || firstHeading || `\u7B2C ${n} \u7AE0`;
519094
+ const fileTitle = tocLabels.get(opfDirKey(item.href)) || firstHeading || UNTITLED_MARK;
519095
+ if (/^(contents|table of contents)$/i.test(fileTitle) && body0.replace(/\s/g, "").length < 4e3)
519096
+ continue;
519097
+ if (body0.replace(/\s/g, "").length < 1500 && /project gutenberg|copyright/i.test(body0))
519098
+ continue;
519099
+ if (/^(版权信息|版权|版权页|著作权|版權)/.test(fileTitle))
519100
+ continue;
519101
+ const colophonFields = (body0.match(/^(书名|作者|译者|编者|丛书|出版社|出版时间|出版年|ISBN|版次|定价|装帧|字数|品牌|出品方)[::]/gm) ?? []).length;
519102
+ if (colophonFields >= 3 && body0.replace(/\s/g, "").length < 2500)
519103
+ continue;
519104
+ if (/^目\s*录$/.test(fileTitle)) {
519105
+ const lines = body0.split("\n").map((l) => l.trim()).filter(Boolean);
519106
+ if (lines.length >= 3 && lines.filter((l) => l.includes("](")).length / lines.length >= 0.6)
519107
+ continue;
519108
+ }
519109
+ const body = sanitizeEpubBody(body0);
519110
+ if (body.replace(/\s/g, "").length < 8)
519111
+ continue;
519112
+ const titleIsLicense = /FULL PROJECT GUTENBERG|LICENSE/i.test(fileTitle);
519113
+ const split = splitChaptersInBody(body, titleIsLicense ? { minHighConf: 1 } : void 0);
519114
+ if (split && split.length >= (titleIsLicense ? 1 : 2)) {
519115
+ for (const seg of split) {
519116
+ chapters.push({
519117
+ path: `chapters/${String(n).padStart(2, "0")}-${sanitizeFileName(seg.title)}.md`,
519118
+ title: seg.title,
519119
+ markdown: `# ${seg.title}
519120
+
519121
+ ${seg.content}`
519122
+ });
519123
+ n++;
519124
+ }
519125
+ n--;
519126
+ continue;
519127
+ }
519128
+ if (titleIsLicense) {
519129
+ if (body.replace(/\s/g, "").length > 2e3) {
519130
+ chapters.push({
519131
+ path: `chapters/${String(n).padStart(2, "0")}-appendix.md`,
519132
+ title: "\u9644\u5F55",
519133
+ markdown: `# \u9644\u5F55
519134
+
519135
+ ${body}`
519136
+ });
519137
+ }
519138
+ continue;
519139
+ }
518917
519140
  chapters.push({
518918
- path: `chapters/${String(n).padStart(2, "0")}-${sanitizeFileName(title)}.md`,
518919
- title,
518920
- markdown: `# ${title}
519141
+ path: `chapters/${String(n).padStart(2, "0")}-${sanitizeFileName(fileTitle)}.md`,
519142
+ title: fileTitle,
519143
+ markdown: `# ${fileTitle}
518921
519144
 
518922
519145
  ${body}`
518923
519146
  });
518924
519147
  }
519148
+ const absorbed = /* @__PURE__ */ new Set();
519149
+ for (let i = 0; i + 1 < chapters.length; i++) {
519150
+ const stub = chapters[i];
519151
+ const next = chapters[i + 1];
519152
+ if (absorbed.has(stub.path))
519153
+ continue;
519154
+ const stubBody = stub.markdown.includes("\n") ? stub.markdown.slice(stub.markdown.indexOf("\n") + 1).trim() : "";
519155
+ if (stub.title === UNTITLED_MARK || stub.title === "\u9644\u5F55")
519156
+ continue;
519157
+ if (stubBody.replace(/\s/g, "").length > 300)
519158
+ continue;
519159
+ if (next.title !== UNTITLED_MARK)
519160
+ continue;
519161
+ const nextBody = next.markdown.includes("\n") ? next.markdown.slice(next.markdown.indexOf("\n") + 1).trim() : next.markdown;
519162
+ chapters[i] = {
519163
+ path: stub.path,
519164
+ title: stub.title,
519165
+ markdown: `# ${stub.title}
519166
+
519167
+ ${stubBody}
519168
+
519169
+ ${nextBody}`
519170
+ };
519171
+ absorbed.add(stub.path);
519172
+ chapters.splice(i + 1, 1);
519173
+ i--;
519174
+ }
518925
519175
  if (chapters.length === 0)
518926
519176
  throw new Error("epub \u91CC\u6CA1\u6709\u53EF\u8BC6\u522B\u7684\u7AE0\u8282\u6587\u672C");
518927
519177
  return { title: bookTitle, chapters };
@@ -518930,13 +519180,27 @@ async function parseEpubFlat(buf) {
518930
519180
  const book = await parseEpub(buf);
518931
519181
  return book.chapters.map((c) => c.markdown.replace(/^# /gm, "## ")).join("\n\n");
518932
519182
  }
518933
- var decoder;
519183
+ var decoder, CH_HEADING, LETTER_HEADING, ROMAN_HEADING, NUM_HEADING, romanValue;
518934
519184
  var init_epub_parser = __esm({
518935
519185
  "src/main/lib/epub-parser.ts"() {
518936
519186
  "use strict";
518937
519187
  init_esm2();
518938
519188
  init_html_article();
518939
519189
  decoder = new TextDecoder("utf-8");
519190
+ CH_HEADING = /^(?:#{1,3}\s*)?(?:CHAPTER|Chapter|chap\.)\s+[IVXLC0-9]{1,7}\b[.:)]?\s*(.*)$/;
519191
+ LETTER_HEADING = /^(?:#{1,3}\s*)?(?:Letter|LETTER)\s+\d{1,3}\b[.:)]?\s*(.*)$/;
519192
+ ROMAN_HEADING = /^(?:#{1,3}\s*)?(?:[—[]\s*)?([IVXLC]{1,7})\s*[—\]]?\.?\s*$/;
519193
+ NUM_HEADING = /^(?:#{1,3}\s*)?[—[]?\s*(\d{1,3})\s*[—\]]?\.?\s*$/;
519194
+ romanValue = (s) => {
519195
+ const vals = { I: 1, V: 5, X: 10, L: 50, C: 100 };
519196
+ let v = 0;
519197
+ for (let i = 0; i < s.length; i++) {
519198
+ const cur = vals[s[i]] ?? 0;
519199
+ const next = vals[s[i + 1]] ?? 0;
519200
+ v += cur < next ? -cur : cur;
519201
+ }
519202
+ return v;
519203
+ };
518940
519204
  }
518941
519205
  });
518942
519206
 
@@ -519488,11 +519752,32 @@ var init_bilibili_wbi = __esm({
519488
519752
  });
519489
519753
 
519490
519754
  // src/main/services/pure/subtitle-parse.ts
519755
+ function decodeEntities(s) {
519756
+ return s.replace(/&([a-z]+);/gi, (m, name18) => ENTITIES[name18.toLowerCase()] ?? m).replace(/&#(\d+);/g, (m, d) => {
519757
+ try {
519758
+ return String.fromCodePoint(Number(d));
519759
+ } catch {
519760
+ return m;
519761
+ }
519762
+ });
519763
+ }
519764
+ function cjkJoin(parts) {
519765
+ let s = "";
519766
+ for (const p of parts) {
519767
+ if (!s) {
519768
+ s = p;
519769
+ continue;
519770
+ }
519771
+ const last = s[s.length - 1];
519772
+ s += CJKISH.test(last) || CJKISH.test(p[0]) ? p : ` ${p}`;
519773
+ }
519774
+ return s;
519775
+ }
519491
519776
  function parseSubtitleToText(raw) {
519492
519777
  const lines = raw.replace(/\r\n/g, "\n").split("\n");
519493
519778
  const out = [];
519779
+ const recent = [];
519494
519780
  let inNote = false;
519495
- let prev = "";
519496
519781
  for (const line of lines) {
519497
519782
  const t = line.trim();
519498
519783
  if (!t) {
@@ -519513,21 +519798,56 @@ function parseSubtitleToText(raw) {
519513
519798
  continue;
519514
519799
  if (/^(Kind:|Language:|Style:|Region:|NOTE)/i.test(t))
519515
519800
  continue;
519516
- const text3 = t.replace(/<[^>]+>/g, "").replace(/&nbsp;/g, " ").trim();
519801
+ let text3 = t.replace(/<[^>]+>/g, "").trim();
519517
519802
  if (!text3)
519518
519803
  continue;
519519
- if (text3 === prev)
519804
+ if (AUTO_MARKERS.test(text3))
519805
+ continue;
519806
+ text3 = decodeEntities(text3);
519807
+ if (recent.includes(text3))
519520
519808
  continue;
519521
- prev = text3;
519522
- out.push(text3);
519809
+ recent.push(text3);
519810
+ if (recent.length > 2)
519811
+ recent.shift();
519812
+ const spoken = text3.replace(/^>{2,}\s*/, "").trim();
519813
+ if (spoken)
519814
+ out.push(spoken);
519815
+ }
519816
+ return cjkJoin(out).replace(/\s+/g, " ").trim();
519817
+ }
519818
+ function pickSubtitleFile(names) {
519819
+ const rank = (n) => {
519820
+ const m = n.toLowerCase().match(/^sub\.(.+)\.(vtt|srt)$/);
519821
+ if (!m)
519822
+ return 99;
519823
+ const lang = m[1];
519824
+ if (lang === "zh-hans" || lang === "zh-cn" || lang.startsWith("zh-hans") || lang.startsWith("zh-cn"))
519825
+ return 0;
519826
+ if (lang === "zh" || lang.startsWith("zh"))
519827
+ return 1;
519828
+ if (lang === "en" || lang.startsWith("en"))
519829
+ return 2;
519830
+ return 3;
519831
+ };
519832
+ let best = null;
519833
+ let bestRank = 99;
519834
+ for (const n of names) {
519835
+ const r = rank(n);
519836
+ if (r < bestRank) {
519837
+ best = n;
519838
+ bestRank = r;
519839
+ }
519523
519840
  }
519524
- return out.join(" ").replace(/\s+/g, " ").trim();
519841
+ return bestRank <= 3 ? best : null;
519525
519842
  }
519526
- var CUE_TIMING;
519843
+ var CUE_TIMING, AUTO_MARKERS, ENTITIES, CJKISH;
519527
519844
  var init_subtitle_parse = __esm({
519528
519845
  "src/main/services/pure/subtitle-parse.ts"() {
519529
519846
  "use strict";
519530
519847
  CUE_TIMING = /^\d{1,2}:\d{2}(?::\d{2})?[.,]\d{3}\s*-->/;
519848
+ AUTO_MARKERS = /^\[(music|applause|laughter|laughs?|silence|inaudible|cheering|foreign|blank[_\s]?audio|music playing|noise)\]$/i;
519849
+ ENTITIES = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: " " };
519850
+ CJKISH = /[\u3000-\u303f\u4e00-\u9fff\uff00-\uffef]/;
519531
519851
  }
519532
519852
  });
519533
519853
 
@@ -519669,7 +519989,7 @@ async function fetchViaYtDlp(url2, dataDir, onProgress, signal) {
519669
519989
  "--no-warnings",
519670
519990
  url2
519671
519991
  ], signal);
519672
- const subFile = (0, import_node_fs6.readdirSync)(workDir).find((f) => /^sub\..*\.(vtt|srt)$/i.test(f));
519992
+ const subFile = pickSubtitleFile((0, import_node_fs6.readdirSync)(workDir));
519673
519993
  if (subFile) {
519674
519994
  const text3 = parseSubtitleToText((0, import_node_fs6.readFileSync)((0, import_node_path6.join)(workDir, subFile), "utf8"));
519675
519995
  if (text3.length > 50) {
@@ -557899,7 +558219,7 @@ function loadSeedData() {
557899
558219
  );
557900
558220
  }
557901
558221
  var SEED_DATA = loadSeedData();
557902
- var SEED_VERSION = 12;
558222
+ var SEED_VERSION = 14;
557903
558223
  function ensureSeedCourse() {
557904
558224
  const result = applySeedData(getDb(), SEED_DATA, SEED_VERSION);
557905
558225
  if (!result.skipped)
@@ -1,4 +1,4 @@
1
- import{r,j as h}from"./index-xynt7zMk.js";import{c as T,u as L,P as D}from"./main-CGE6fm01.js";/**
1
+ import{r,j as h}from"./index-C-4sKCSr.js";import{c as T,u as L,P as D}from"./main-D3HpSUyK.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-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";/**
1
+ import{r as s,j as t}from"./index-C-4sKCSr.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-D3HpSUyK.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-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";/**
1
+ import{r as u,j as t}from"./index-C-4sKCSr.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-D3HpSUyK.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-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";/**
1
+ import{r as o,h as U,j as e,c as ie}from"./index-C-4sKCSr.js";import{c as te,u as ce,a as j,h as de,T as z,i as Y,L as V,j as oe,X as xe}from"./main-D3HpSUyK.js";import{R as G}from"./rotate-ccw-C3k3pTDh.js";import{A as q}from"./arrow-right-B0QrRNSR.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-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(`
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./index-CODVWHV0.js","./index-CU6ublfJ.js","./index-C-4sKCSr.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-D3HpSUyK.js";import{r as o,j as a}from"./index-C-4sKCSr.js";import{C as w}from"./CanvasStage-u_7YeGk1.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-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};
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-CODVWHV0.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-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};
1
+ import{r,j as e,c as S}from"./index-C-4sKCSr.js";import{u as y,a as j,S as M}from"./main-D3HpSUyK.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};