dsh-plugin-lookatstudy 0.12.4 → 0.12.5

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.
package/lib/client.js CHANGED
@@ -235,6 +235,9 @@ window.__ModuleLoader__.load({
235
235
  .lks-zone-h{font-size:14px;color:var(--dsw-alias-label-secondary);margin:0 0 8px;font-weight:600}
236
236
  .lks-note{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:10px 14px;margin-bottom:8px}
237
237
  .lks-note .lks-note-src{float:right;font-size:11.5px;color:var(--dsw-alias-label-secondary)}
238
+ .lks-note-del{float:right;clear:right;border:none;background:none;color:var(--dsw-alias-label-tertiary);cursor:pointer;padding:2px;border-radius:5px;line-height:0}
239
+ .lks-note-del:hover{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2)}
240
+ .lks-note-del.armed{color:#fff;background:var(--dsw-alias-state-error-primary)}
238
241
  .lks-note .lks-note-title{font-weight:600;font-size:13px}
239
242
  .lks-note .lks-note-text{margin-top:4px;font-size:13px;color:var(--dsw-alias-label-secondary);line-height:1.65}
240
243
  .lks-note .lks-note-text p{margin:4px 0}
@@ -715,6 +718,18 @@ window.__ModuleLoader__.load({
715
718
  });
716
719
  this.refresh();
717
720
  }
721
+ /** Delete one notebook entry from a lesson's Cornell zones. */
722
+ async deleteNote(lessonId, noteId) {
723
+ await fetchJson("/lookatstudy/api/note/delete", {
724
+ method: "POST",
725
+ headers: { "content-type": "application/json" },
726
+ body: JSON.stringify({
727
+ lessonId,
728
+ noteId
729
+ })
730
+ });
731
+ this.refresh();
732
+ }
718
733
  };
719
734
  /** The one shared store instance backing every study seat component. */
720
735
  const studyStore = new StudyStore();
@@ -727,6 +742,7 @@ window.__ModuleLoader__.load({
727
742
  setFocus: studyStore.setFocus.bind(studyStore),
728
743
  searchLessons: studyStore.searchLessons.bind(studyStore),
729
744
  deleteCourse: studyStore.deleteCourse.bind(studyStore),
745
+ deleteNote: studyStore.deleteNote.bind(studyStore),
730
746
  bindLessonSession: studyStore.bindLessonSession.bind(studyStore)
731
747
  };
732
748
  }
@@ -1567,6 +1583,8 @@ window.__ModuleLoader__.load({
1567
1583
  "rail.delete": "删除本课程",
1568
1584
  "rail.delete.confirm": "确认删除?",
1569
1585
  "rail.delete.title.confirm": "再点一次确认删除(含全部进度与笔记)。反悔前可先在设置页备份状态文件",
1586
+ "note.delete": "删除本条笔记",
1587
+ "note.delete.confirm": "确认删除?",
1570
1588
  "rail.section.collapse": "折叠本章节",
1571
1589
  "rail.section.expand": "展开本章节({count} 课时)",
1572
1590
  "rail.section.count": "{count} 课",
@@ -1687,6 +1705,8 @@ window.__ModuleLoader__.load({
1687
1705
  "rail.delete": "Delete this course",
1688
1706
  "rail.delete.confirm": "Delete?",
1689
1707
  "rail.delete.title.confirm": "Click again to confirm (all progress and notes included). Back up via the state file in Settings first",
1708
+ "note.delete": "Delete this note",
1709
+ "note.delete.confirm": "Delete?",
1690
1710
  "rail.section.collapse": "Collapse this section",
1691
1711
  "rail.section.expand": "Expand this section ({count} lessons)",
1692
1712
  "rail.section.count": "{count} lessons",
@@ -2149,7 +2169,7 @@ window.__ModuleLoader__.load({
2149
2169
  }
2150
2170
  /** Tab body: the factory-bound ctx carries workspaces/sessions for the per-lesson session jumps. */
2151
2171
  function StudyTab({ inputActions, ctx, ...standard }) {
2152
- const { data, activate, setMode, setFocus, searchLessons, deleteCourse, bindLessonSession } = useStudy();
2172
+ const { data, activate, setMode, setFocus, searchLessons, deleteCourse, deleteNote, bindLessonSession } = useStudy();
2153
2173
  const chatLegacy = standard.useChat?.((s) => s.legacy);
2154
2174
  const sessionSnapshot = standard.useSession?.((s) => s);
2155
2175
  const snapshot = pickTranscript(chatLegacy, sessionSnapshot);
@@ -2257,7 +2277,10 @@ window.__ModuleLoader__.load({
2257
2277
  setMode,
2258
2278
  send,
2259
2279
  snapshot
2260
- }), (0, react.createElement)(BlackboardColumn, { data })));
2280
+ }), (0, react.createElement)(BlackboardColumn, {
2281
+ data,
2282
+ deleteNote
2283
+ })));
2261
2284
  }
2262
2285
  /** Left column: course management (pick/delete/search/import), lesson tree, due box. */
2263
2286
  function CourseRail({ data, activate, setFocus, searchLessons, deleteCourse, bindLessonSession, send, ctx, currentSessionId }) {
@@ -2601,9 +2624,33 @@ window.__ModuleLoader__.load({
2601
2624
  }, s.label))) : null, (0, react.createElement)(ActionError, { error }));
2602
2625
  }
2603
2626
  /** Right column: the blackboard — focus-lesson 讲解/脑图/概念图 plus the Cornell 笔记. */
2604
- function BlackboardColumn({ data }) {
2627
+ function BlackboardColumn({ data, deleteNote }) {
2605
2628
  const lesson = data?.lesson ?? null;
2606
2629
  const [pane, setPane] = (0, react.useState)("teach");
2630
+ const [error, setError] = (0, react.useState)(null);
2631
+ const [armedNote, setArmedNote] = (0, react.useState)(null);
2632
+ (0, react.useEffect)(() => {
2633
+ if (armedNote === null) return;
2634
+ const disarm = () => {
2635
+ setArmedNote(null);
2636
+ };
2637
+ const onKey = (e) => {
2638
+ if (e.key === "Escape") disarm();
2639
+ };
2640
+ window.addEventListener("click", disarm);
2641
+ window.addEventListener("keydown", onKey);
2642
+ return () => {
2643
+ window.removeEventListener("click", disarm);
2644
+ window.removeEventListener("keydown", onKey);
2645
+ };
2646
+ }, [armedNote]);
2647
+ const fire = (action) => {
2648
+ action.then(() => {
2649
+ setError(null);
2650
+ }, (err) => {
2651
+ setError(err instanceof Error ? err.message : String(err));
2652
+ });
2653
+ };
2607
2654
  const proseRef = (0, react.useRef)(null);
2608
2655
  const diagRef = (0, react.useRef)(null);
2609
2656
  (0, react.useEffect)(() => {
@@ -2659,11 +2706,24 @@ window.__ModuleLoader__.load({
2659
2706
  }, (0, react.createElement)("div", { className: "lks-zone-h" }, tr(labelKey)), ...lesson.notes.filter((n) => n.zone === zone).map((n) => (0, react.createElement)("div", {
2660
2707
  key: n.id,
2661
2708
  className: "lks-note"
2662
- }, (0, react.createElement)("span", { className: "lks-note-src" }, n.source), (0, react.createElement)("div", { className: "lks-note-title" }, n.title), (0, react.createElement)("div", {
2709
+ }, (0, react.createElement)("span", { className: "lks-note-src" }, n.source), (0, react.createElement)("button", {
2710
+ className: `lks-note-del${armedNote === n.id ? " armed" : ""}`,
2711
+ title: armedNote === n.id ? tr("note.delete.confirm") : tr("note.delete"),
2712
+ "aria-label": armedNote === n.id ? tr("note.delete.confirm") : tr("note.delete"),
2713
+ onClick: (e) => {
2714
+ e.stopPropagation();
2715
+ if (armedNote !== n.id) {
2716
+ setArmedNote(n.id);
2717
+ return;
2718
+ }
2719
+ setArmedNote(null);
2720
+ fire(deleteNote(lesson.lessonId, n.id));
2721
+ }
2722
+ }, (0, react.createElement)(IconTrashOutline16, { size: 12 })), (0, react.createElement)("div", { className: "lks-note-title" }, n.title), (0, react.createElement)("div", {
2663
2723
  className: "lks-note-text",
2664
2724
  dangerouslySetInnerHTML: { __html: renderMarkdown(n.text) }
2665
2725
  }), n.quote !== null ? (0, react.createElement)("div", { className: "lks-note-q" }, `“${n.quote}”`) : null))))));
2666
- return (0, react.createElement)("div", { className: "lks-col lks-col-bb" }, (0, react.createElement)("div", { className: "lks-colhead" }, tr("col.bb")), body);
2726
+ return (0, react.createElement)("div", { className: "lks-col lks-col-bb" }, (0, react.createElement)("div", { className: "lks-colhead" }, tr("col.bb")), body, (0, react.createElement)(ActionError, { error }));
2667
2727
  }
2668
2728
  //#endregion
2669
2729
  //#region src/client/starter.tsx