dsh-plugin-lookatstudy 0.16.0 → 0.17.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.
- package/lib/client.js +400 -137
- package/lib/client.js.map +1 -1
- package/lib/index.mjs +10 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -301,6 +301,156 @@ window.__ModuleLoader__.load({
|
|
|
301
301
|
.lks-ui .lks14-search{background:rgb(0 0 0/0.25);border:1px solid rgb(255 255 255/0.15);color:var(--ink-strong);border-radius:10px}
|
|
302
302
|
.lks-ui .lks14-search:focus{border-color:var(--brand);outline:none}
|
|
303
303
|
.lks-ui .lks14-search::placeholder{color:rgb(var(--ink-rgb)/0.35)}
|
|
304
|
+
|
|
305
|
+
/* ══════════ A-track (P10a): island zeroing — the 27+6 un-skinned leftovers ══════════ */
|
|
306
|
+
/* buttons reset to UA buttontext/buttonface (black/light) — the panel's ink must flow through */
|
|
307
|
+
.lks-ui button{color:inherit;background-color:transparent;border-color:transparent}
|
|
308
|
+
/* A6 token completion: rgb-channel companions + concept-map palette (upstream :root) */
|
|
309
|
+
.lks-ui{--brand-dark-rgb:70 163 2;--brand-light-rgb:126 217 87;
|
|
310
|
+
--accent-dark-rgb:10 140 220;--accent-light-rgb:94 212 255;
|
|
311
|
+
--gold-dark-rgb:217 158 0;--gold-light-rgb:255 230 128;
|
|
312
|
+
--warning-dark-rgb:230 43 43;--warning-light-rgb:255 117 117;
|
|
313
|
+
--exam-dark-rgb:126 34 206;--exam-light-rgb:192 132 252;
|
|
314
|
+
--cm-c0-fill:#1C3352;--cm-c0-line:#6F9FD4;--cm-c1-fill:#1F3A29;--cm-c1-line:#7FB37F;
|
|
315
|
+
--cm-c2-fill:#42301A;--cm-c2-line:#CFA05E;--cm-c3-fill:#3D3620;--cm-c3-line:#CBB75E;
|
|
316
|
+
--cm-c4-fill:#33294A;--cm-c4-line:#A48DCB}
|
|
317
|
+
/* A1 in-chat quiz options (click = send answer; neutral pill, hover brand) */
|
|
318
|
+
.lks-ui .lks14-opt{background:rgb(var(--ink-rgb)/0.05);border:2px solid transparent;color:var(--ink)}
|
|
319
|
+
.lks-ui .lks14-opt:hover{border-color:var(--brand);background:rgb(var(--ink-rgb)/0.05)}
|
|
320
|
+
.lks-ui .lks14-optletter{color:var(--brand-light)}
|
|
321
|
+
.lks-ui .lks14-starter{background:transparent;border:1px solid var(--border-faint);color:var(--ink-muted)}
|
|
322
|
+
.lks-ui .lks14-starter:hover{background:rgb(var(--ink-rgb)/0.06);color:var(--ink);border-color:var(--border)}
|
|
323
|
+
.lks-ui .lks14-chatlesson{color:var(--ink-muted)}
|
|
324
|
+
.lks-ui .lks14-meta{color:var(--ink-muted)}
|
|
325
|
+
.lks-ui .lks14-dueitem{color:var(--ink-muted)}
|
|
326
|
+
.lks-ui .lks14-hint{color:var(--ink-faint)}
|
|
327
|
+
.lks-ui .lks-readbar-notice{color:var(--ink-faint)}
|
|
328
|
+
.lks-ui .lks-cmap-legend{color:var(--ink-muted)}
|
|
329
|
+
/* A2 quiz-card body family */
|
|
330
|
+
.lks-ui .lks-qcard-prompt{color:var(--ink)}
|
|
331
|
+
.lks-ui .lks-qcard-count{color:var(--ink-faint)}
|
|
332
|
+
.lks-ui .lks-qcard-ans{color:var(--ink-faint)}
|
|
333
|
+
.lks-ui .lks-qcard-expl{color:var(--ink-muted);border-left-color:var(--accent)}
|
|
334
|
+
.lks-ui .lks-qcard-prompt.review.wrong{color:var(--warning-light)}
|
|
335
|
+
.lks-ui .lks-qcard-q.review{border-bottom-color:var(--border)}
|
|
336
|
+
/* A2 artifact bits */
|
|
337
|
+
.lks-ui .lks-acard-expand{color:var(--ink-faint);border:none;background:none}
|
|
338
|
+
.lks-ui .lks-acard-expand:hover{color:var(--ink);background:rgb(var(--ink-rgb)/0.06)}
|
|
339
|
+
.lks-ui .lks-acard-modal-title{color:var(--ink-strong)}
|
|
340
|
+
.lks-ui .lks-acard-guess-prompt{color:var(--ink)}
|
|
341
|
+
.lks-ui .lks-acard-guess-wait{color:var(--ink-faint)}
|
|
342
|
+
.lks-ui .lks-acard-note b{color:var(--ink-strong)}
|
|
343
|
+
.lks-ui .lks-acard-stage{border-top-color:var(--border)}
|
|
344
|
+
/* A2 note family */
|
|
345
|
+
.lks-ui .lks-note-text{color:var(--ink-muted)}
|
|
346
|
+
.lks-ui .lks-note-text th,.lks-ui .lks-note-text td{border-color:var(--border)}
|
|
347
|
+
.lks-ui .lks-note-src{color:var(--ink-faint)}
|
|
348
|
+
.lks-ui .lks-note-del{color:var(--ink-faint)}
|
|
349
|
+
.lks-ui .lks-note-del:hover{color:var(--warning-light);background:rgb(var(--warning-rgb)/0.08)}
|
|
350
|
+
.lks-ui .lks-note-del.armed{color:#fff;background:var(--warning)}
|
|
351
|
+
.lks-ui .lks-note-q{color:var(--ink-muted)}
|
|
352
|
+
.lks-ui .lks-note-title{color:var(--ink-strong)}
|
|
353
|
+
/* A3 selection popover → surface-0 floating card */
|
|
354
|
+
.lks-ui .lks-quote-btn{background:var(--surface-0);border:1px solid var(--border);box-shadow:0 4px 12px -2px rgb(var(--shadow-rgb)/0.14),0 1px 3px -1px rgb(var(--shadow-rgb)/0.08);border-radius:10px;overflow:hidden;animation:lks-confirm-enter 160ms var(--ease-out-back)}
|
|
355
|
+
.lks-ui .lks-quote-btn button{color:var(--ink)}
|
|
356
|
+
.lks-ui .lks-quote-btn button:hover{background:rgb(var(--ink-rgb)/0.06)}
|
|
357
|
+
.lks-ui .lks-quote-btn button + button{border-left-color:var(--border)}
|
|
358
|
+
/* A4 prose links / markers / strong / hr */
|
|
359
|
+
.lks-ui .lks14-prose a,.lks-ui .lks-note-text a{color:rgb(var(--accent-rgb));text-decoration:none;font-weight:500}
|
|
360
|
+
.lks-ui .lks14-prose a:hover,.lks-ui .lks-note-text a:hover{text-decoration:underline}
|
|
361
|
+
.lks-ui .lks14-prose li::marker,.lks-ui .lks-note-text li::marker{color:rgb(var(--brand-rgb))}
|
|
362
|
+
.lks-ui .lks14-prose strong,.lks-ui .lks-note-text strong{color:var(--ink-strong)}
|
|
363
|
+
.lks-ui .lks14-prose hr,.lks-ui .lks-note-text hr{border-color:var(--border)}
|
|
364
|
+
/* A8 table borders inside bubbles/cards/notes */
|
|
365
|
+
.lks-ui .lks14-msg-assistant th,.lks-ui .lks14-msg-assistant td{border-color:var(--border)}
|
|
366
|
+
.lks-ui .lks-acard-table th,.lks-ui .lks-acard-table td{border-color:var(--border)}
|
|
367
|
+
.lks-ui .lks-acard-table th{border-bottom-color:var(--brand)}
|
|
368
|
+
/* A5 scoped scrollbar (host-light chrome otherwise scrolls inside dark columns) */
|
|
369
|
+
.lks-ui ::-webkit-scrollbar{width:8px;height:8px}
|
|
370
|
+
.lks-ui ::-webkit-scrollbar-track{background:transparent}
|
|
371
|
+
.lks-ui ::-webkit-scrollbar-thumb{background:var(--border);border-radius:9999px;border:2px solid transparent;background-clip:padding-box}
|
|
372
|
+
.lks-ui ::-webkit-scrollbar-thumb:hover{background:var(--surface-3);background-clip:padding-box}
|
|
373
|
+
/* A7 feedback/ambient animations (upstream values verbatim) */
|
|
374
|
+
@keyframes lks-crown-sparkle{0%,100%{transform:scale(1);filter:drop-shadow(0 0 0 var(--gold))}50%{transform:scale(1.08);filter:drop-shadow(0 0 6px var(--gold-glow))}}
|
|
375
|
+
.lks-ui .lks-bubble-mastered .lks-bubble-glyph{animation:lks-crown-sparkle 1.6s ease-in-out infinite;display:inline-flex}
|
|
376
|
+
@keyframes lks-energy-breathe{0%,100%{opacity:.78;filter:drop-shadow(0 0 0 var(--gold))}50%{opacity:1;filter:drop-shadow(0 0 4px var(--gold-glow))}}
|
|
377
|
+
@keyframes lks-flame-flicker{0%,100%{transform:scale(1) rotate(-2deg)}25%{transform:scale(1.06) rotate(1deg)}50%{transform:scale(.97) rotate(-1deg)}75%{transform:scale(1.04) rotate(2deg)}}
|
|
378
|
+
.lks-ui .lks-hdr-xp .lks-hdr-glyph{display:inline-flex;animation:lks-energy-breathe 2s ease-in-out infinite}
|
|
379
|
+
.lks-ui .lks-hdr-streak .lks-hdr-glyph{display:inline-flex;animation:lks-flame-flicker 1.2s ease-in-out infinite}
|
|
380
|
+
@keyframes lks-answer-correct{0%{transform:scale(1)}40%{transform:scale(1.05)}100%{transform:scale(1)}}
|
|
381
|
+
@keyframes lks-answer-wrong{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-3px)}40%,80%{transform:translateX(3px)}}
|
|
382
|
+
.lks-ui .lks-qcard-opt.right{animation:lks-answer-correct 350ms var(--ease-spring)}
|
|
383
|
+
.lks-ui .lks-qcard-opt.wrong{animation:lks-answer-wrong 320ms ease-in-out}
|
|
384
|
+
@keyframes lks-confirm-enter{from{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}
|
|
385
|
+
/* A7 toast enter/exit at upstream values (replaces the base sheet's simplified pair) */
|
|
386
|
+
@keyframes lks-toast-in-up{from{opacity:0;transform:translateY(-12px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}
|
|
387
|
+
@keyframes lks-toast-out-up{from{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:translateY(-8px) scale(.97)}}
|
|
388
|
+
.lks-ui .lks-toast{animation:lks-toast-in-up 220ms var(--ease-out-back)}
|
|
389
|
+
.lks-ui .lks-toast.exiting{animation:lks-toast-out-up 180ms var(--ease-out-quart) forwards}
|
|
390
|
+
.lks-ui .lks-toast-close{color:var(--ink-faint)}
|
|
391
|
+
.lks-ui .lks-toast-close:hover{color:var(--ink);background:rgb(var(--ink-rgb)/0.08)}
|
|
392
|
+
/* search rows: complete the half-covered pair */
|
|
393
|
+
.lks-ui .lks14-searchrow{border-bottom-color:var(--border)}
|
|
394
|
+
.lks-ui .lks14-searchrow-title{color:var(--ink-strong)}
|
|
395
|
+
.lks-ui .lks14-searchrow-course{color:var(--ink-faint)}
|
|
396
|
+
|
|
397
|
+
/* ══════════ B-track (P10b): the upstream rail frame + column skeletons ══════════ */
|
|
398
|
+
/* the floating topbar (absolute over the scrolling panes) */
|
|
399
|
+
.lks-ui .lks14-railtop{position:absolute;top:0;left:0;right:0;z-index:40;padding:8px;pointer-events:none}
|
|
400
|
+
.lks-ui .lks-railtabs,.lks-ui .lks14-railhead{pointer-events:auto}
|
|
401
|
+
.lks-ui .lks-railtabs{display:flex;padding:4px;border-radius:10px;gap:4px;margin-bottom:8px;
|
|
402
|
+
background:rgb(var(--surface-rail-rgb)/0.55);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px)}
|
|
403
|
+
.lks-ui .lks-railtab{flex:1;display:flex;align-items:center;justify-content:center;padding:6px 0;border-radius:8px;
|
|
404
|
+
font-size:12.5px;font-weight:700;color:rgb(255 255 255/0.5)}
|
|
405
|
+
.lks-ui .lks-railtab.on{background:rgb(var(--brand-rgb)/0.2);color:var(--brand)}
|
|
406
|
+
/* the glass title card: title row / mastery row / entry pills row */
|
|
407
|
+
.lks-ui .lks14-railhead{display:flex;flex-direction:column;gap:6px}
|
|
408
|
+
.lks-ui .lks14-railcard-row{display:flex;align-items:center;gap:8px}
|
|
409
|
+
.lks-ui .lks14-railpct{flex:none;font-size:12px;font-weight:800;color:#fff;font-variant-numeric:tabular-nums;text-shadow:0 1px 3px rgba(0,0,0,0.6)}
|
|
410
|
+
.lks-ui .lks14-masterybar{flex:1}
|
|
411
|
+
.lks-ui .lks-railpill{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;border-radius:999px;
|
|
412
|
+
background:rgb(255 255 255/0.05);box-shadow:inset 0 0 0 1px rgb(255 255 255/0.1);color:rgb(var(--ink-rgb)/0.6);font-size:11px;font-weight:700}
|
|
413
|
+
.lks-ui .lks-railpill:hover{background:rgb(255 255 255/0.1)}
|
|
414
|
+
.lks-ui .lks-railpill.due{background:rgb(var(--review-rgb)/0.2);box-shadow:inset 0 0 0 1px rgb(var(--review-rgb)/0.3);color:var(--review)}
|
|
415
|
+
.lks-ui .lks-railpill-n{font-weight:800;font-variant-numeric:tabular-nums}
|
|
416
|
+
/* the sliding two-pane body */
|
|
417
|
+
.lks-ui .lks14-railbody{position:absolute;inset:0;overflow:hidden;z-index:10}
|
|
418
|
+
.lks-ui .lks14-railtrack{display:flex;height:100%;width:200%;transition:transform .3s var(--ease-out-expo)}
|
|
419
|
+
.lks-ui .lks14-railpane{width:50%;height:100%;position:relative}
|
|
420
|
+
.lks-ui .lks14-railscroll{height:100%;overflow-y:auto;overflow-x:hidden;padding:196px 8px 16px}
|
|
421
|
+
.lks-ui .lks-mapsec-list{display:flex;flex-direction:column;gap:24px}
|
|
422
|
+
.lks-ui .lks-mapsec{padding:12px 8px 0}
|
|
423
|
+
.lks-ui .lks14-railpane-import{height:100%;overflow-y:auto;padding:64px 12px 12px}
|
|
424
|
+
.lks-ui .lks14-raillist{display:flex;flex-direction:column;gap:8px;margin-bottom:10px}
|
|
425
|
+
.lks-ui .lks14-railcourse{text-align:left;padding:10px 12px;border-radius:12px;background:rgb(255 255 255/0.05);display:flex;flex-direction:column;gap:2px}
|
|
426
|
+
.lks-ui .lks14-railcourse:hover{background:rgb(255 255 255/0.1)}
|
|
427
|
+
.lks-ui .lks14-railcourse.on{background:rgb(var(--brand-rgb)/0.12);box-shadow:inset 0 0 0 1px rgb(var(--brand-rgb)/0.4)}
|
|
428
|
+
.lks-ui .lks14-railcourse-title{font-size:13px;font-weight:700;color:var(--ink-strong);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
429
|
+
.lks-ui .lks14-railcourse.on .lks14-railcourse-title{color:var(--brand)}
|
|
430
|
+
.lks-ui .lks14-railcourse-sub{font-size:10.5px;color:rgb(var(--ink-rgb)/0.4)}
|
|
431
|
+
.lks-ui .lks14-raildemo{margin-bottom:10px}
|
|
432
|
+
/* the full-rail overlays (search / review) */
|
|
433
|
+
.lks-ui .lks-railoverlay{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;gap:8px;padding:12px;overflow-y:auto;
|
|
434
|
+
background:rgb(var(--surface-rail-rgb)/0.92);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}
|
|
435
|
+
.lks-ui .lks-railoverlay-head{display:flex;gap:8px;align-items:center}
|
|
436
|
+
.lks-ui .lks-railoverlay-head .lks14-search{flex:1}
|
|
437
|
+
/* chat: thin current-lesson row (ThreadSwitcher empty-state voice) */
|
|
438
|
+
.lks-ui .lks14-lessonrow{flex:none;padding:6px 14px;font-size:12px;font-weight:700;color:var(--ink-muted);opacity:.75}
|
|
439
|
+
/* composer: the soul pills ride the capsule's first row */
|
|
440
|
+
.lks-ui .lks14-soulrow{display:flex;align-items:center;gap:6px;padding:0 2px 6px}
|
|
441
|
+
.lks-ui .lks14-soullabel{flex:none;font-size:11px;color:var(--ink-faint)}
|
|
442
|
+
/* B6: assistant text is full-width prose (no card); user bubbles right-align */
|
|
443
|
+
.lks-ui .lks14-msg-assistant{background:none;border:none;box-shadow:none;border-radius:0;padding:0;max-width:80ch;font-size:.9375rem}
|
|
444
|
+
.lks-ui .lks14-msg-assistant.streaming{border:none;opacity:.85}
|
|
445
|
+
.lks-ui .lks14-msg-user{align-self:flex-end;max-width:85%}
|
|
446
|
+
/* B8: the empty state is a centered card with a 3D CTA */
|
|
447
|
+
.lks-ui .lks14-emptycard{margin:auto;display:flex;flex-direction:column;align-items:center;gap:10px;text-align:center;padding:24px;max-width:320px}
|
|
448
|
+
.lks-ui .lks14-emptycard-title{font-size:1rem;font-weight:800;color:var(--ink-strong)}
|
|
449
|
+
.lks-ui .lks14-emptycard-hint{font-size:.825rem;color:var(--ink-muted);line-height:1.6}
|
|
450
|
+
/* B5: notebook tab capsule + 960px reading column */
|
|
451
|
+
.lks-ui .lks14-notebody{margin:0 auto;max-width:960px;width:100%;padding:12px 20px 24px;box-sizing:border-box}
|
|
452
|
+
.lks-ui .lks14-viewtabs{background:rgb(var(--ink-rgb)/0.08);border-radius:999px;padding:3px;align-self:flex-start}
|
|
453
|
+
.lks-ui .lks14-readbar{position:sticky;top:0;z-index:20;background:var(--surface-2);border-radius:10px}
|
|
304
454
|
`;
|
|
305
455
|
//#endregion
|
|
306
456
|
//#region src/client/styles.ts
|
|
@@ -362,10 +512,9 @@ html[data-dsh-lookatstudy-active] [class*='centerCol'] > :not([data-dsh-lookatst
|
|
|
362
512
|
.lks14-righthalf{flex:1;min-width:0;display:flex;flex-direction:column;min-height:0}
|
|
363
513
|
.lks14-row{flex:1;min-height:0;display:flex}
|
|
364
514
|
.lks14-col{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden}
|
|
365
|
-
.lks14-colhead{flex:none;display:flex;align-items:center;gap:8px;padding:10px 12px;font-size:13px;font-weight:600;color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1)}
|
|
366
515
|
|
|
367
516
|
/* 左 rail: course picker, tree, review, import */
|
|
368
|
-
.lks14-rail{flex:0 0
|
|
517
|
+
.lks14-rail{flex:0 0 300px;border-right:none;padding:0;overflow:hidden;position:relative}
|
|
369
518
|
.lks14-railhead{display:flex;align-items:center;gap:6px;margin-top:10px}
|
|
370
519
|
.lks14-railtitle{font-weight:600;font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}
|
|
371
520
|
.lks14-railsub{font-size:12px;color:var(--dsw-alias-label-secondary);margin:6px 0}
|
|
@@ -383,13 +532,13 @@ html[data-dsh-lookatstudy-active] [class*='centerCol'] > :not([data-dsh-lookatst
|
|
|
383
532
|
.lks14-hint{font-size:11.5px;color:var(--dsw-alias-label-tertiary);margin-top:6px;line-height:1.6}
|
|
384
533
|
|
|
385
534
|
/* 中 chat: the tutor stream + its own composer (upstream ChatStream/ChatComposer) */
|
|
386
|
-
.lks14-chat{flex:
|
|
535
|
+
.lks14-chat{flex:0 0 auto;width:clamp(480px,45%,800px);min-width:0;border-right:none}
|
|
387
536
|
.lks14-chatlesson{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;color:var(--dsw-alias-label-tertiary)}
|
|
388
537
|
.lks14-pills{display:inline-flex;gap:2px}
|
|
389
538
|
.lks14-pill{border:none;background:none;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:12px;padding:2px 8px;border-radius:7px;cursor:pointer}
|
|
390
539
|
.lks14-pill:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}
|
|
391
540
|
.lks14-pill.on{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}
|
|
392
|
-
.lks14-stream{flex:1;overflow-y:auto;padding:
|
|
541
|
+
.lks14-stream{flex:1;overflow-y:auto;padding:20px 20px 24px;display:flex;flex-direction:column;gap:24px}
|
|
393
542
|
.lks14-msg{max-width:92%;line-height:1.65;font-size:13.5px}
|
|
394
543
|
.lks14-msg-user{align-self:flex-end;background:var(--dsw-alias-bg-layer-2);border-radius:12px 12px 3px 12px;padding:7px 11px;white-space:pre-wrap}
|
|
395
544
|
.lks14-msg-assistant{align-self:flex-start;background:var(--dsw-alias-bg-layer-1);border-radius:12px 12px 12px 3px;padding:8px 12px}
|
|
@@ -404,7 +553,7 @@ html[data-dsh-lookatstudy-active] [class*='centerCol'] > :not([data-dsh-lookatst
|
|
|
404
553
|
.lks14-opt:hover{background:var(--dsw-alias-bg-layer-2)}
|
|
405
554
|
.lks14-opt:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}
|
|
406
555
|
.lks14-optletter{flex:none;font-weight:700;color:var(--dsw-alias-business-primary)}
|
|
407
|
-
.lks14-starters{flex:none;display:flex;flex-wrap:
|
|
556
|
+
.lks14-starters{flex:none;display:flex;flex-wrap:nowrap;gap:6px;padding:0 20px 6px;overflow-x:auto}
|
|
408
557
|
.lks14-starter{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;border-radius:14px;padding:3px 10px;cursor:pointer}
|
|
409
558
|
.lks14-starter:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}
|
|
410
559
|
.lks14-starter:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}
|
|
@@ -414,11 +563,11 @@ html[data-dsh-lookatstudy-active] [class*='centerCol'] > :not([data-dsh-lookatst
|
|
|
414
563
|
.lks14-composertext:focus{outline:none;border-color:var(--dsw-alias-state-business-primary)}
|
|
415
564
|
|
|
416
565
|
/* 右 notebook: 讲解/概念图/笔记 (upstream NotebookPanel) */
|
|
417
|
-
.lks14-note{flex:
|
|
566
|
+
.lks14-note{flex:1 1 auto;min-width:440px;padding:0;overflow-y:auto}
|
|
418
567
|
.lks14-lessonhead{margin:10px 0 6px}
|
|
419
568
|
.lks14-lessonhead h2{margin:0 0 4px;font-size:16px}
|
|
420
569
|
.lks14-meta{font-size:12px;color:var(--dsw-alias-label-secondary);margin:2px 0}
|
|
421
|
-
.lks14-viewtabs{display:flex;gap:2px;margin:
|
|
570
|
+
.lks14-viewtabs{display:flex;gap:2px;margin:0 0 12px}
|
|
422
571
|
.lks14-viewtab{border:none;background:none;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:12.5px;padding:4px 10px;border-radius:8px;cursor:pointer;display:inline-flex;align-items:center;gap:4px}
|
|
423
572
|
.lks14-viewtab:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-state-business-primary);outline:none}
|
|
424
573
|
.lks14-viewtab.on{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}
|
|
@@ -489,7 +638,7 @@ html[data-dsh-lookatstudy-active] [class*='centerCol'] > :not([data-dsh-lookatst
|
|
|
489
638
|
.lks14-switch{display:flex}
|
|
490
639
|
.lks14-body{flex-direction:column}
|
|
491
640
|
.lks14-rail{flex:none;max-height:32vh;border-right:none;border-bottom:1px solid var(--dsw-alias-border-l1)}
|
|
492
|
-
.lks14-chat{min-width:0}
|
|
641
|
+
.lks14-chat{min-width:0;width:auto;flex:1 1 auto}
|
|
493
642
|
.lks14-note{flex:1 1 auto;min-height:0}
|
|
494
643
|
.lks14-body[data-pane='rail'] .lks14-righthalf{display:none}
|
|
495
644
|
.lks14-body[data-pane='chat'] .lks14-rail,.lks14-body[data-pane='chat'] .lks14-note,
|
|
@@ -890,6 +1039,51 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
890
1039
|
fill: "currentColor"
|
|
891
1040
|
}));
|
|
892
1041
|
}
|
|
1042
|
+
/** IconArrowUpFill16 — the 3D send button glyph (upstream: lucide Send direction) */
|
|
1043
|
+
function IconArrowUpFill16({ size = 16, className }) {
|
|
1044
|
+
return (0, react.createElement)("svg", {
|
|
1045
|
+
width: size,
|
|
1046
|
+
height: size,
|
|
1047
|
+
className,
|
|
1048
|
+
viewBox: "0 0 16 16",
|
|
1049
|
+
fill: "none",
|
|
1050
|
+
xmlns: "http://www.w3.org/2000/svg"
|
|
1051
|
+
}, (0, react.createElement)("path", {
|
|
1052
|
+
d: "M8 2.6 13.2 8h-3v5.4H5.8V8h-3L8 2.6Z",
|
|
1053
|
+
fill: "currentColor"
|
|
1054
|
+
}));
|
|
1055
|
+
}
|
|
1056
|
+
/** IconCloseFill16 — toast/modal close */
|
|
1057
|
+
function IconCloseFill16({ size = 16, className }) {
|
|
1058
|
+
return (0, react.createElement)("svg", {
|
|
1059
|
+
width: size,
|
|
1060
|
+
height: size,
|
|
1061
|
+
className,
|
|
1062
|
+
viewBox: "0 0 16 16",
|
|
1063
|
+
fill: "none",
|
|
1064
|
+
xmlns: "http://www.w3.org/2000/svg"
|
|
1065
|
+
}, (0, react.createElement)("path", {
|
|
1066
|
+
d: "M3.4 2 2 3.4 6.6 8 2 12.6 3.4 14 8 9.4l4.6 4.6 1.4-1.4L9.4 8 14 3.4 12.6 2 8 6.6 3.4 2Z",
|
|
1067
|
+
fill: "currentColor"
|
|
1068
|
+
}));
|
|
1069
|
+
}
|
|
1070
|
+
/** IconMaximizeOutline16 — artifact expand (upstream: lucide Maximize2 corners) */
|
|
1071
|
+
function IconMaximizeOutline16({ size = 16, className }) {
|
|
1072
|
+
return (0, react.createElement)("svg", {
|
|
1073
|
+
width: size,
|
|
1074
|
+
height: size,
|
|
1075
|
+
className,
|
|
1076
|
+
viewBox: "0 0 16 16",
|
|
1077
|
+
fill: "none",
|
|
1078
|
+
xmlns: "http://www.w3.org/2000/svg"
|
|
1079
|
+
}, (0, react.createElement)("path", {
|
|
1080
|
+
d: "M9.5 2H14v4.5M6.5 14H2V9.5M14 2 9.2 6.8M2 14l4.8-4.8",
|
|
1081
|
+
stroke: "currentColor",
|
|
1082
|
+
"stroke-width": 1.6,
|
|
1083
|
+
"stroke-linecap": "round",
|
|
1084
|
+
"stroke-linejoin": "round"
|
|
1085
|
+
}));
|
|
1086
|
+
}
|
|
893
1087
|
//#endregion
|
|
894
1088
|
//#region src/client/data.ts
|
|
895
1089
|
/**
|
|
@@ -2001,6 +2195,15 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
2001
2195
|
"map.node.locked": "锁定 — 先完成前面的课时",
|
|
2002
2196
|
"map.node.due": "到了复习时间",
|
|
2003
2197
|
"map.exam.locked": "考试未解锁 — 本章节全部课时掌握度 ≥50% 后开放",
|
|
2198
|
+
"map.tab.map": "地图",
|
|
2199
|
+
"map.tab.import": "导入",
|
|
2200
|
+
"map.search.label": "搜索",
|
|
2201
|
+
"map.review.label": "复习",
|
|
2202
|
+
"map.overlay.close": "关闭",
|
|
2203
|
+
"chat.start": "开始学习",
|
|
2204
|
+
"chat.start.hint": "从当前课时的第一个开场动作开始",
|
|
2205
|
+
"prompt.start": "你好,我们开始学这一课吧:先给我一个两三句话的导览,再从第一个知识点讲起。",
|
|
2206
|
+
"mode.label": "风格:",
|
|
2004
2207
|
"companion.poke": "戳一戳伴学伙伴",
|
|
2005
2208
|
"companion.poked": "伴学伙伴向你眨了眨眼",
|
|
2006
2209
|
"companion.form.ember": "小焰",
|
|
@@ -2028,6 +2231,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
2028
2231
|
"rail.due": "待复习 {count}",
|
|
2029
2232
|
"rail.due.over": "超{days}天",
|
|
2030
2233
|
"rail.due.start": "开始复习",
|
|
2234
|
+
"rail.due.none": "暂时没有到期的复习,保持节奏!",
|
|
2031
2235
|
"rail.due.tag": "这课时的复习今天到期(SM-2)",
|
|
2032
2236
|
"rail.delete": "删除本课程",
|
|
2033
2237
|
"rail.delete.confirm": "确认删除?",
|
|
@@ -2204,6 +2408,15 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
2204
2408
|
"map.node.locked": "Locked — finish the previous lessons first",
|
|
2205
2409
|
"map.node.due": "Due for review",
|
|
2206
2410
|
"map.exam.locked": "Exam locked — every lesson in this section needs ≥50% mastery",
|
|
2411
|
+
"map.tab.map": "Map",
|
|
2412
|
+
"map.tab.import": "Import",
|
|
2413
|
+
"map.search.label": "Search",
|
|
2414
|
+
"map.review.label": "Review",
|
|
2415
|
+
"map.overlay.close": "Close",
|
|
2416
|
+
"chat.start": "Start learning",
|
|
2417
|
+
"chat.start.hint": "Begin with this lesson’s first starter move",
|
|
2418
|
+
"prompt.start": "Hi — let’s start this lesson: give me a two-sentence tour, then begin with the first concept.",
|
|
2419
|
+
"mode.label": "Style: ",
|
|
2207
2420
|
"companion.poke": "Poke the companion",
|
|
2208
2421
|
"companion.poked": "The companion winks at you",
|
|
2209
2422
|
"companion.form.ember": "Ember",
|
|
@@ -2231,6 +2444,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
2231
2444
|
"rail.due": "{count} due",
|
|
2232
2445
|
"rail.due.over": "{days}d overdue",
|
|
2233
2446
|
"rail.due.start": "Start reviewing",
|
|
2447
|
+
"rail.due.none": "Nothing due right now — keep the streak!",
|
|
2234
2448
|
"rail.due.tag": "this lesson's review is due today (SM-2)",
|
|
2235
2449
|
"rail.delete": "Delete this course",
|
|
2236
2450
|
"rail.delete.confirm": "Delete?",
|
|
@@ -3375,7 +3589,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
3375
3589
|
onClick: () => {
|
|
3376
3590
|
setExpanded(true);
|
|
3377
3591
|
}
|
|
3378
|
-
},
|
|
3592
|
+
}, (0, react.createElement)(IconMaximizeOutline16, { size: 13 }))), body, expanded ? (0, react.createElement)("div", {
|
|
3379
3593
|
className: "lks-acard-modal",
|
|
3380
3594
|
onClick: () => {
|
|
3381
3595
|
setExpanded(false);
|
|
@@ -3390,7 +3604,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
3390
3604
|
onClick: () => {
|
|
3391
3605
|
setExpanded(false);
|
|
3392
3606
|
}
|
|
3393
|
-
},
|
|
3607
|
+
}, (0, react.createElement)(IconCloseFill16, { size: 13 }))), failed ? (0, react.createElement)("pre", { className: "lks-acard-code" }, mermaid) : (0, react.createElement)("div", { ref: (el) => {
|
|
3394
3608
|
if (el !== null) renderMermaidInto(el, mermaid, () => {
|
|
3395
3609
|
setFailed(true);
|
|
3396
3610
|
});
|
|
@@ -4381,10 +4595,10 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
4381
4595
|
}), (0, react.createElement)("div", { className: "lks14-righthalf" }, (0, react.createElement)("div", { className: "lks14-appheader" }, (0, react.createElement)("span", { className: "lks-hdr-title" }, lesson?.courseTitle ?? tr("tab.label")), (0, react.createElement)("span", {
|
|
4382
4596
|
className: "lks-hdr-xp",
|
|
4383
4597
|
title: tr("header.xp", { xp: progress?.totalXp ?? 0 })
|
|
4384
|
-
}, (0, react.createElement)("span", { className: "lks-hdr-stat" },
|
|
4598
|
+
}, (0, react.createElement)("span", { className: "lks-hdr-stat lks-hdr-glyph" }, (0, react.createElement)(IconBoltFill16, { size: 14 })), (0, react.createElement)("span", { className: "lks-hdr-xpbar" }, (0, react.createElement)("i", { style: { width: `${Math.min(100, progress?.levelPct ?? 0)}%` } }))), (0, react.createElement)("span", {
|
|
4385
4599
|
className: "lks-hdr-stat lks-hdr-streak",
|
|
4386
4600
|
title: tr("header.streak")
|
|
4387
|
-
}, "
|
|
4601
|
+
}, (0, react.createElement)("span", { className: "lks-hdr-glyph" }, (0, react.createElement)(IconFlameFill16, { size: 14 })), String(progress?.streak ?? 0)), (0, react.createElement)("span", {
|
|
4388
4602
|
className: "lks-hdr-stat",
|
|
4389
4603
|
title: tr("header.level")
|
|
4390
4604
|
}, `Lv${String(progress?.level ?? 1)}`)), (0, react.createElement)("div", { className: "lks14-row" }, (0, react.createElement)(ChatPane, {
|
|
@@ -4469,7 +4683,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
4469
4683
|
onClick: () => {
|
|
4470
4684
|
toastStore.startExit(t.id);
|
|
4471
4685
|
}
|
|
4472
|
-
},
|
|
4686
|
+
}, (0, react.createElement)(IconCloseFill16, { size: 12 })))));
|
|
4473
4687
|
}
|
|
4474
4688
|
/** Module-level shell handle so the panel can suppress hand-back on internal opens. */
|
|
4475
4689
|
const PANEL_SHELL = { current: null };
|
|
@@ -4489,8 +4703,10 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
4489
4703
|
}));
|
|
4490
4704
|
};
|
|
4491
4705
|
const [confirmDelete, setConfirmDelete] = (0, react.useState)(false);
|
|
4492
|
-
const [showImport, setShowImport] = (0, react.useState)(false);
|
|
4493
4706
|
const [error, setError] = (0, react.useState)(null);
|
|
4707
|
+
const [panel, setPanel] = (0, react.useState)("map");
|
|
4708
|
+
const [searchOpen, setSearchOpen] = (0, react.useState)(false);
|
|
4709
|
+
const [reviewOpen, setReviewOpen] = (0, react.useState)(false);
|
|
4494
4710
|
const reportError = (err) => {
|
|
4495
4711
|
setError(err instanceof Error ? err.message : String(err));
|
|
4496
4712
|
};
|
|
@@ -4539,121 +4755,162 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
4539
4755
|
data,
|
|
4540
4756
|
searchLessons
|
|
4541
4757
|
]);
|
|
4542
|
-
const
|
|
4543
|
-
|
|
4544
|
-
|
|
4758
|
+
const courseId = data !== null && data.courses.length > 0 ? data.courses.some((c) => c.courseId === selectedCourse) ? selectedCourse : data.courses[0].courseId : null;
|
|
4759
|
+
const course = data?.courses.find((c) => c.courseId === courseId) ?? null;
|
|
4760
|
+
const topbar = data === null ? null : (0, react.createElement)("div", { className: "lks14-railtop" }, (0, react.createElement)("div", { className: "lks-railtabs" }, ...["map", "import"].map((tab) => (0, react.createElement)("button", {
|
|
4761
|
+
key: tab,
|
|
4762
|
+
className: `lks-railtab${panel === tab ? " on" : ""}`,
|
|
4763
|
+
"aria-pressed": String(panel === tab),
|
|
4545
4764
|
onClick: () => {
|
|
4546
|
-
|
|
4765
|
+
setPanel(tab);
|
|
4547
4766
|
}
|
|
4548
|
-
}, (0, react.createElement)(
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
if (!confirmDelete) {
|
|
4570
|
-
setConfirmDelete(true);
|
|
4571
|
-
return;
|
|
4572
|
-
}
|
|
4573
|
-
setConfirmDelete(false);
|
|
4574
|
-
deleteCourse(courseId).then(() => {
|
|
4575
|
-
setSelectedCourse("");
|
|
4576
|
-
}, reportError);
|
|
4767
|
+
}, tr(tab === "map" ? "map.tab.map" : "map.tab.import")))), panel === "map" && course !== null ? (0, react.createElement)("div", { className: "lks14-railhead" }, (0, react.createElement)("div", { className: "lks14-railcard-row" }, data.courses.length > 1 ? (0, react.createElement)("select", {
|
|
4768
|
+
className: "lks-set-select",
|
|
4769
|
+
value: courseId ?? "",
|
|
4770
|
+
onChange: (e) => {
|
|
4771
|
+
setSelectedCourse(e.target.value);
|
|
4772
|
+
setConfirmDelete(false);
|
|
4773
|
+
}
|
|
4774
|
+
}, ...data.courses.map((c) => (0, react.createElement)("option", {
|
|
4775
|
+
key: c.courseId,
|
|
4776
|
+
value: c.courseId
|
|
4777
|
+
}, c.title))) : (0, react.createElement)("div", {
|
|
4778
|
+
className: "lks14-railtitle",
|
|
4779
|
+
title: course.title
|
|
4780
|
+
}, course.title), (0, react.createElement)("button", {
|
|
4781
|
+
className: `lks-btn ${confirmDelete ? "primary" : "ghost"}`,
|
|
4782
|
+
title: confirmDelete ? tr("rail.delete.title.confirm") : tr("rail.delete"),
|
|
4783
|
+
onClick: (e) => {
|
|
4784
|
+
e.stopPropagation();
|
|
4785
|
+
if (!confirmDelete) {
|
|
4786
|
+
setConfirmDelete(true);
|
|
4787
|
+
return;
|
|
4577
4788
|
}
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4789
|
+
setConfirmDelete(false);
|
|
4790
|
+
deleteCourse(courseId ?? "").then(() => {
|
|
4791
|
+
setSelectedCourse("");
|
|
4792
|
+
}, reportError);
|
|
4793
|
+
}
|
|
4794
|
+
}, confirmDelete ? tr("rail.delete.confirm") : (0, react.createElement)(IconTrashOutline16, { size: 14 }))), (0, react.createElement)("div", { className: "lks14-railcard-row" }, (0, react.createElement)("div", {
|
|
4795
|
+
className: `lks14-masterybar${course.avgMasteryPct === 100 ? " gold" : ""}`,
|
|
4796
|
+
title: course.avgMasteryPct === null ? tr("rail.avg.none") : tr("rail.avg", { pct: course.avgMasteryPct })
|
|
4797
|
+
}, (0, react.createElement)("i", { style: { transform: `scaleX(${(course.avgMasteryPct ?? 0) / 100})` } })), (0, react.createElement)("span", { className: "lks14-railpct" }, `${String(course.avgMasteryPct ?? 0)}%`)), (0, react.createElement)("div", { className: "lks14-railcard-row" }, (0, react.createElement)("button", {
|
|
4798
|
+
className: "lks-railpill",
|
|
4799
|
+
title: tr("rail.search"),
|
|
4800
|
+
onClick: () => {
|
|
4801
|
+
setSearchOpen(true);
|
|
4802
|
+
}
|
|
4803
|
+
}, (0, react.createElement)(IconGlobeOutline14, { size: 13 }), tr("map.search.label")), (0, react.createElement)("button", {
|
|
4804
|
+
className: `lks-railpill${data.dueCount > 0 ? " due" : ""}`,
|
|
4805
|
+
title: data.dueCount > 0 ? tr("rail.due", { count: data.dueCount }) : tr("map.review.label"),
|
|
4806
|
+
onClick: () => {
|
|
4807
|
+
setReviewOpen(true);
|
|
4808
|
+
}
|
|
4809
|
+
}, (0, react.createElement)(IconBookFill16, { size: 13 }), tr("map.review.label"), data.dueCount > 0 ? (0, react.createElement)("span", { className: "lks-railpill-n" }, String(data.dueCount)) : null))) : null);
|
|
4810
|
+
const mapPane = data === null ? (0, react.createElement)("div", { className: "lks14-empty" }, tr("loading")) : course === null ? null : (0, react.createElement)("div", { className: "lks14-railscroll" }, (0, react.createElement)("div", { className: "lks-mapsec-list" }, ...course.sections.flatMap((section) => {
|
|
4811
|
+
const examAllowed = examOpen(section.lessons);
|
|
4812
|
+
const lessons = section.lessons.filter((l) => query.trim() === "" || titleMatches(l.title, query) || l.focus);
|
|
4813
|
+
if (lessons.length === 0) return [];
|
|
4814
|
+
const open = query.trim() !== "" || effectiveOpen(section.title, sectionDefaultOpen(section), sectionOverrides);
|
|
4815
|
+
return [(0, react.createElement)(MapSectionView, {
|
|
4816
|
+
key: section.title,
|
|
4817
|
+
section: {
|
|
4818
|
+
title: section.title,
|
|
4819
|
+
index: section.index,
|
|
4820
|
+
lessons
|
|
4591
4821
|
},
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
if (first !== void 0) {
|
|
4600
|
-
setQuery("");
|
|
4601
|
-
setSearchRows([]);
|
|
4602
|
-
setFocus(first.lessonId).catch(reportError);
|
|
4603
|
-
}
|
|
4822
|
+
examAllowed,
|
|
4823
|
+
open,
|
|
4824
|
+
onToggle: () => {
|
|
4825
|
+
toggleSection(section.title, !open);
|
|
4826
|
+
},
|
|
4827
|
+
onJump: (id) => {
|
|
4828
|
+
setFocus(id).catch(reportError);
|
|
4604
4829
|
}
|
|
4605
|
-
})
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4830
|
+
})];
|
|
4831
|
+
})));
|
|
4832
|
+
const importPane = data === null ? null : (0, react.createElement)("div", { className: "lks14-railpane-import" }, data.courses.length > 1 ? (0, react.createElement)("div", { className: "lks14-raillist" }, ...data.courses.map((c) => (0, react.createElement)("button", {
|
|
4833
|
+
key: c.courseId,
|
|
4834
|
+
className: `lks14-railcourse${c.courseId === courseId ? " on" : ""}`,
|
|
4835
|
+
onClick: () => {
|
|
4836
|
+
setSelectedCourse(c.courseId);
|
|
4837
|
+
setPanel("map");
|
|
4838
|
+
}
|
|
4839
|
+
}, (0, react.createElement)("span", { className: "lks14-railcourse-title" }, c.title), (0, react.createElement)("span", { className: "lks14-railcourse-sub" }, tr("rail.mastered", {
|
|
4840
|
+
mastered: c.mastered,
|
|
4841
|
+
total: c.total
|
|
4842
|
+
}))))) : null, data.courses.length === 0 ? (0, react.createElement)("div", { className: "lks14-empty" }, tr("rail.empty.title")) : null, (0, react.createElement)("button", {
|
|
4843
|
+
className: "lks-btn ghost lks14-raildemo",
|
|
4844
|
+
onClick: () => {
|
|
4845
|
+
send(tr("prompt.import", { url: "https://github.com/microsoft/AI-For-Beginners" }));
|
|
4846
|
+
}
|
|
4847
|
+
}, (0, react.createElement)(IconDownloadOutline16, null), tr("rail.empty.demo")), (0, react.createElement)(ImportRow, { send }));
|
|
4848
|
+
const searchOverlay = searchOpen && data !== null ? (0, react.createElement)("div", { className: "lks-railoverlay" }, (0, react.createElement)("div", { className: "lks-railoverlay-head" }, (0, react.createElement)("input", {
|
|
4849
|
+
className: "lks14-search",
|
|
4850
|
+
type: "search",
|
|
4851
|
+
placeholder: tr("rail.search"),
|
|
4852
|
+
value: query,
|
|
4853
|
+
autoFocus: true,
|
|
4854
|
+
onChange: (e) => {
|
|
4855
|
+
setQuery(e.target.value);
|
|
4856
|
+
},
|
|
4857
|
+
onKeyDown: (e) => {
|
|
4858
|
+
if (e.key === "Escape") {
|
|
4610
4859
|
setQuery("");
|
|
4611
4860
|
setSearchRows([]);
|
|
4612
|
-
|
|
4613
|
-
}
|
|
4614
|
-
}, (0, react.createElement)("span", { className: "lks14-searchrow-title" }, row.title), row.courseTitle !== "" ? (0, react.createElement)("span", { className: "lks14-searchrow-course" }, row.courseTitle) : null, row.snippet !== "" ? (0, react.createElement)("span", { className: "lks14-searchrow-snip" }, row.snippet) : null))) : null, data.dueCount > 0 ? (0, react.createElement)("div", { className: "lks14-duebox" }, (0, react.createElement)(IconRefreshOutline16, { size: 13 }), tr("rail.due", { count: data.dueCount }), ...data.due.map((d) => (0, react.createElement)("button", {
|
|
4615
|
-
key: d.lessonId,
|
|
4616
|
-
className: "lks14-dueitem",
|
|
4617
|
-
title: tr("review.jump"),
|
|
4618
|
-
onClick: () => {
|
|
4619
|
-
setFocus(d.lessonId).catch(reportError);
|
|
4861
|
+
setSearchOpen(false);
|
|
4620
4862
|
}
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
const examAllowed = examOpen(section.lessons);
|
|
4629
|
-
const lessons = section.lessons.filter((l) => query.trim() === "" || titleMatches(l.title, query) || l.focus);
|
|
4630
|
-
if (lessons.length === 0) return [];
|
|
4631
|
-
const open = query.trim() !== "" || effectiveOpen(section.title, sectionDefaultOpen(section), sectionOverrides);
|
|
4632
|
-
return [(0, react.createElement)(MapSectionView, {
|
|
4633
|
-
key: section.title,
|
|
4634
|
-
section: {
|
|
4635
|
-
title: section.title,
|
|
4636
|
-
index: section.index,
|
|
4637
|
-
lessons
|
|
4638
|
-
},
|
|
4639
|
-
examAllowed,
|
|
4640
|
-
open,
|
|
4641
|
-
onToggle: () => {
|
|
4642
|
-
toggleSection(section.title, !open);
|
|
4643
|
-
},
|
|
4644
|
-
onJump: (id) => {
|
|
4645
|
-
setFocus(id).catch(reportError);
|
|
4646
|
-
}
|
|
4647
|
-
})];
|
|
4648
|
-
}), (0, react.createElement)("button", {
|
|
4649
|
-
className: "lks-btn ghost",
|
|
4650
|
-
style: { marginTop: "10px" },
|
|
4651
|
-
onClick: () => {
|
|
4652
|
-
setShowImport(!showImport);
|
|
4863
|
+
if (e.key !== "Enter" || query.trim() === "") return;
|
|
4864
|
+
const first = searchRows[0];
|
|
4865
|
+
if (first !== void 0) {
|
|
4866
|
+
setQuery("");
|
|
4867
|
+
setSearchRows([]);
|
|
4868
|
+
setSearchOpen(false);
|
|
4869
|
+
setFocus(first.lessonId).catch(reportError);
|
|
4653
4870
|
}
|
|
4654
|
-
}
|
|
4655
|
-
})()
|
|
4656
|
-
|
|
4871
|
+
}
|
|
4872
|
+
}), (0, react.createElement)("button", {
|
|
4873
|
+
className: "lks-btn ghost",
|
|
4874
|
+
onClick: () => {
|
|
4875
|
+
setQuery("");
|
|
4876
|
+
setSearchRows([]);
|
|
4877
|
+
setSearchOpen(false);
|
|
4878
|
+
}
|
|
4879
|
+
}, tr("map.overlay.close"))), searchRows.length > 0 ? (0, react.createElement)("div", { className: "lks14-searchpanel" }, ...searchRows.map((row) => (0, react.createElement)("button", {
|
|
4880
|
+
key: row.lessonId,
|
|
4881
|
+
className: "lks14-searchrow",
|
|
4882
|
+
title: tr("rail.search.jump"),
|
|
4883
|
+
onClick: () => {
|
|
4884
|
+
setQuery("");
|
|
4885
|
+
setSearchRows([]);
|
|
4886
|
+
setSearchOpen(false);
|
|
4887
|
+
setFocus(row.lessonId).catch(reportError);
|
|
4888
|
+
}
|
|
4889
|
+
}, (0, react.createElement)("span", { className: "lks14-searchrow-title" }, row.title), row.courseTitle !== "" ? (0, react.createElement)("span", { className: "lks14-searchrow-course" }, row.courseTitle) : null, row.snippet !== "" ? (0, react.createElement)("span", { className: "lks14-searchrow-snip" }, row.snippet) : null))) : null) : null;
|
|
4890
|
+
const reviewOverlay = reviewOpen && data !== null ? (0, react.createElement)("div", { className: "lks-railoverlay" }, (0, react.createElement)("div", { className: "lks-railoverlay-head" }, (0, react.createElement)("span", { className: "lks14-railtitle" }, data.dueCount > 0 ? tr("rail.due", { count: data.dueCount }) : tr("map.review.label")), (0, react.createElement)("button", {
|
|
4891
|
+
className: "lks-btn ghost",
|
|
4892
|
+
onClick: () => {
|
|
4893
|
+
setReviewOpen(false);
|
|
4894
|
+
}
|
|
4895
|
+
}, tr("map.overlay.close"))), ...data.due.map((d) => (0, react.createElement)("button", {
|
|
4896
|
+
key: d.lessonId,
|
|
4897
|
+
className: "lks14-dueitem",
|
|
4898
|
+
title: tr("review.jump"),
|
|
4899
|
+
onClick: () => {
|
|
4900
|
+
setFocus(d.lessonId).catch(reportError);
|
|
4901
|
+
}
|
|
4902
|
+
}, (0, react.createElement)("span", null, d.lessonTitle), d.overdueDays > 0 ? (0, react.createElement)("span", { className: "lks14-over" }, tr("rail.due.over", { days: d.overdueDays })) : null)), data.dueCount > 0 ? (0, react.createElement)("button", {
|
|
4903
|
+
className: "lks-btn primary",
|
|
4904
|
+
onClick: () => {
|
|
4905
|
+
setReviewOpen(false);
|
|
4906
|
+
send(tr("prompt.review"));
|
|
4907
|
+
}
|
|
4908
|
+
}, tr("rail.due.start")) : (0, react.createElement)("div", { className: "lks14-empty" }, tr("rail.due.none"))) : null;
|
|
4909
|
+
const effectivePanel = data !== null && data.courses.length === 0 ? "import" : panel;
|
|
4910
|
+
return (0, react.createElement)("div", { className: `lks14-col lks14-rail${courseId !== null ? ` lks-sky-${pickSky(courseId)}` : ""}` }, topbar, (0, react.createElement)("div", { className: "lks14-railbody" }, (0, react.createElement)("div", {
|
|
4911
|
+
className: "lks14-railtrack",
|
|
4912
|
+
style: { transform: effectivePanel === "map" ? "translateX(0)" : "translateX(-50%)" }
|
|
4913
|
+
}, (0, react.createElement)("div", { className: "lks14-railpane" }, mapPane), (0, react.createElement)("div", { className: "lks14-railpane" }, importPane))), searchOverlay, reviewOverlay, (0, react.createElement)("div", { className: "lks-propcard-err" }, error));
|
|
4657
4914
|
}
|
|
4658
4915
|
function ImportRow({ send }) {
|
|
4659
4916
|
const [url, setUrl] = (0, react.useState)("");
|
|
@@ -4719,20 +4976,17 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
4719
4976
|
onClick: () => {
|
|
4720
4977
|
send(tr("proposal.decline.msg", { lesson: proposal.lessonTitle }));
|
|
4721
4978
|
}
|
|
4722
|
-
}, tr("proposal.decline"))) : null, (0, react.createElement)("div", { className: "lks14-
|
|
4723
|
-
key: mode.id,
|
|
4724
|
-
className: `lks14-pill${data?.mode === mode.id ? " on" : ""}`,
|
|
4725
|
-
"aria-pressed": String(data?.mode === mode.id),
|
|
4726
|
-
"aria-disabled": dormant || void 0,
|
|
4727
|
-
title: dormant ? tr("tutor.dormant") : tr(mode.hintKey),
|
|
4728
|
-
onClick: () => {
|
|
4729
|
-
if (!dormant) fire(setMode(mode.id));
|
|
4730
|
-
}
|
|
4731
|
-
}, tr(mode.labelKey))))), (0, react.createElement)("div", {
|
|
4979
|
+
}, tr("proposal.decline"))) : null, lesson !== null || !dormant ? (0, react.createElement)("div", { className: "lks14-lessonrow" }, lesson !== null ? (0, react.createElement)("span", null, lesson.title) : (0, react.createElement)("span", null, tr("col.tutor"))) : null, (0, react.createElement)("div", {
|
|
4732
4980
|
className: "lks14-stream",
|
|
4733
4981
|
ref: streamEl,
|
|
4734
4982
|
"data-lks-feed": rows.length > 0 ? `rows:${String(rows.length)}` : bound ? feedAttached ? "attached-empty" : "waiting" : "no-thread"
|
|
4735
|
-
}, rows.length === 0 ? (0, react.createElement)("div", { className: "lks14-
|
|
4983
|
+
}, rows.length === 0 ? (0, react.createElement)("div", { className: "lks14-emptycard" }, (0, react.createElement)("div", { className: "lks14-emptycard-title" }, dormant ? tr("tutor.dormant") : tr("tutor.empty")), (0, react.createElement)("div", { className: "lks14-emptycard-hint" }, tr("tutor.empty.hint")), !dormant ? (0, react.createElement)("button", {
|
|
4984
|
+
className: "lks-btn primary",
|
|
4985
|
+
title: tr("chat.start.hint"),
|
|
4986
|
+
onClick: () => {
|
|
4987
|
+
send(starters[0]?.message ?? tr("prompt.start"));
|
|
4988
|
+
}
|
|
4989
|
+
}, tr("chat.start")) : null) : rows.map((row, i) => chatRow(row, !dormant && i === lastAssistant ? { send } : void 0)), rows.length > 0 && rows[rows.length - 1].role === "user" ? (0, react.createElement)("div", { className: "lks14-thinking" }, (0, react.createElement)("i", null), (0, react.createElement)("i", null), (0, react.createElement)("i", null)) : null), ...(lesson?.artifacts ?? []).filter((a) => a.artifactType === "quiz").map((a) => (0, react.createElement)(QuizCard, {
|
|
4736
4990
|
key: a.id,
|
|
4737
4991
|
lessonId: lesson.lessonId,
|
|
4738
4992
|
artifactId: a.id,
|
|
@@ -4746,7 +5000,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
4746
5000
|
key: a.id,
|
|
4747
5001
|
artifact: a,
|
|
4748
5002
|
send
|
|
4749
|
-
})), (0, react.createElement)("div", { className: "lks14-starters" }, ...starters.map((s) => (0, react.createElement)("button", {
|
|
5003
|
+
})), rows.length > 0 ? (0, react.createElement)("div", { className: "lks14-starters" }, ...starters.map((s) => (0, react.createElement)("button", {
|
|
4750
5004
|
key: s.label,
|
|
4751
5005
|
className: "lks14-starter",
|
|
4752
5006
|
"aria-disabled": dormant || void 0,
|
|
@@ -4754,7 +5008,16 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
4754
5008
|
onClick: () => {
|
|
4755
5009
|
if (!dormant) send(s.message);
|
|
4756
5010
|
}
|
|
4757
|
-
}, s.label))), (0, react.createElement)("div", { className: "lks14-composer" }, (0, react.createElement)("div", { className: "lks14-composer-card" }, (0, react.createElement)("
|
|
5011
|
+
}, s.label))) : null, (0, react.createElement)("div", { className: "lks14-composer" }, (0, react.createElement)("div", { className: "lks14-composer-card" }, (0, react.createElement)("div", { className: "lks14-soulrow" }, (0, react.createElement)("span", { className: "lks14-soullabel" }, tr("mode.label")), (0, react.createElement)("span", { className: "lks14-pills" }, ...MODES$1.map((mode) => (0, react.createElement)("button", {
|
|
5012
|
+
key: mode.id,
|
|
5013
|
+
className: `lks14-pill${data?.mode === mode.id ? " on" : ""}`,
|
|
5014
|
+
"aria-pressed": String(data?.mode === mode.id),
|
|
5015
|
+
"aria-disabled": dormant || void 0,
|
|
5016
|
+
title: dormant ? tr("tutor.dormant") : tr(mode.hintKey),
|
|
5017
|
+
onClick: () => {
|
|
5018
|
+
if (!dormant) fire(setMode(mode.id));
|
|
5019
|
+
}
|
|
5020
|
+
}, mode.id === "direct" ? (0, react.createElement)(IconBoltFill16, { size: 12 }) : mode.id === "guide" ? (0, react.createElement)(IconGoalOutline16, { size: 12 }) : (0, react.createElement)(IconBookFill16, { size: 12 }), tr(mode.labelKey))))), (0, react.createElement)("textarea", {
|
|
4758
5021
|
className: "lks14-composertext",
|
|
4759
5022
|
placeholder: busy ? tr("composer.busy") : tr("tutor.empty.hint"),
|
|
4760
5023
|
value: draft,
|
|
@@ -4774,7 +5037,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
4774
5037
|
}, busy ? (0, react.createElement)(IconLoadingOutline16, {
|
|
4775
5038
|
size: 16,
|
|
4776
5039
|
className: "lks-spin"
|
|
4777
|
-
}) :
|
|
5040
|
+
}) : (0, react.createElement)(IconArrowUpFill16, { size: 18 }))), sendError !== null || error !== null ? (0, react.createElement)("div", { className: "lks-propcard-err" }, sendError ?? error) : null));
|
|
4778
5041
|
}
|
|
4779
5042
|
/** 右栏:the notebook — 讲解/概念图/笔记 tabs (upstream NotebookPanel arrangement). */
|
|
4780
5043
|
function NotebookPane({ data, deleteNote, send, companionEvent }) {
|
|
@@ -5004,7 +5267,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
5004
5267
|
setEnhanceTick(Date.now());
|
|
5005
5268
|
});
|
|
5006
5269
|
}, [tab, lesson?.html]);
|
|
5007
|
-
const body = lesson === null ? (0, react.createElement)("div", { className: "lks14-empty" }, tr("bb.empty"), (0, react.createElement)("br"), tr("bb.empty.hint")) : (0, react.createElement)("div", { className: "lks14-notebody" }, (0, react.createElement)("div", { className: "lks14-
|
|
5270
|
+
const body = lesson === null ? (0, react.createElement)("div", { className: "lks14-empty" }, tr("bb.empty"), (0, react.createElement)("br"), tr("bb.empty.hint")) : (0, react.createElement)("div", { className: "lks14-notebody" }, (0, react.createElement)("div", { className: "lks14-viewtabs" }, (0, react.createElement)("button", {
|
|
5008
5271
|
className: `lks14-viewtab${tab === "teach" ? " on" : ""}`,
|
|
5009
5272
|
"aria-pressed": String(tab === "teach"),
|
|
5010
5273
|
onClick: () => {
|
|
@@ -5027,7 +5290,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
5027
5290
|
setUnseenTick(Date.now());
|
|
5028
5291
|
}
|
|
5029
5292
|
}
|
|
5030
|
-
}, tr("bb.notes"), unseen.length > 0 ? (0, react.createElement)("span", { className: "lks-viewtab-badge" }, String(unseen.length)) : null)), tab === "teach" ? (0, react.createElement)("div", null, lesson.due ? (0, react.createElement)("div", {
|
|
5293
|
+
}, tr("bb.notes"), unseen.length > 0 ? (0, react.createElement)("span", { className: "lks-viewtab-badge" }, String(unseen.length)) : null)), tab !== "notes" ? (0, react.createElement)("div", { className: "lks14-lessonhead" }, (0, react.createElement)("h2", null, lesson.title), (0, react.createElement)("div", { className: "lks14-meta" }, `${lesson.courseTitle} · ${statusTitle("study", lesson.status)}` + (lesson.masteryPct === null ? "" : ` · ${tr("bb.mastery", { pct: lesson.masteryPct })}`))) : null, tab === "teach" ? (0, react.createElement)("div", null, lesson.due ? (0, react.createElement)("div", {
|
|
5031
5294
|
className: "lks-ratecard",
|
|
5032
5295
|
"data-lks-rate": lesson.lessonId
|
|
5033
5296
|
}, (0, react.createElement)("div", { className: "lks-ratecard-title" }, tr("review.rate.title")), (0, react.createElement)("div", { className: "lks-ratecard-opts" }, ...[
|
|
@@ -5145,7 +5408,7 @@ mark.lks-hl{background:var(--dsw-alias-state-warn-tertiary);color:inherit;border
|
|
|
5145
5408
|
className: "lks-note-text",
|
|
5146
5409
|
dangerouslySetInnerHTML: { __html: renderMarkdown(n.text) }
|
|
5147
5410
|
}), n.quote !== null ? (0, react.createElement)("div", { className: "lks-note-q" }, `“${n.quote}”`) : null))))));
|
|
5148
|
-
return (0, react.createElement)("div", { className: "lks14-col lks14-note" },
|
|
5411
|
+
return (0, react.createElement)("div", { className: "lks14-col lks14-note" }, body, (0, react.createElement)("div", { className: "lks-propcard-err" }, error));
|
|
5149
5412
|
}
|
|
5150
5413
|
//#endregion
|
|
5151
5414
|
//#region src/client/shell-entry.ts
|