修改文字堆砌的问题
This commit is contained in:
@@ -849,9 +849,43 @@ collapsible-section[open] > :not(.head) .chatpapers-lecture-root {
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: color-mix(in srgb, currentColor 32%, transparent) transparent;
|
scrollbar-color: color-mix(in srgb, currentColor 32%, transparent) transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatpapers-lecture-beat-list.chatpapers-lecture-scroll-y {
|
||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 段落列表:单行省略;详情区:换行(二者作用域分离) */
|
||||||
|
.chatpapers-lecture-beat-list .chatpapers-lecture-beat-line {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatpapers-lecture-beat-list .chatpapers-lecture-beat-label {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.3;
|
||||||
|
opacity: 0.72;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatpapers-lecture-beat-list .chatpapers-lecture-beat-preview {
|
||||||
|
flex: 1 1 0;
|
||||||
|
width: 0;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-beat-list.chatpapers-lecture-scroll-y::-webkit-scrollbar,
|
.chatpapers-lecture-beat-list.chatpapers-lecture-scroll-y::-webkit-scrollbar,
|
||||||
.chatpapers-lecture-para-detail.chatpapers-lecture-scroll-y::-webkit-scrollbar {
|
.chatpapers-lecture-para-detail.chatpapers-lecture-scroll-y::-webkit-scrollbar {
|
||||||
width: 5px;
|
width: 5px;
|
||||||
@@ -1062,19 +1096,32 @@ collapsible-section[open] > :not(.head) .chatpapers-lecture-root {
|
|||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-para-original.is-active-sentence {
|
.chatpapers-lecture-beat-list .chatpapers-lecture-sentence-item {
|
||||||
|
max-height: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatpapers-lecture-beat-list .chatpapers-lecture-sentence-item .chatpapers-lecture-beat-main {
|
||||||
|
max-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatpapers-lecture-para-detail .chatpapers-lecture-para-original.is-active-sentence {
|
||||||
|
display: block;
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-bottom: 8px;
|
||||||
border-left: 3px solid #1f7a8c;
|
border-left: 3px solid #1f7a8c;
|
||||||
padding-left: 8px;
|
padding: 6px 8px;
|
||||||
background: color-mix(in srgb, #1f7a8c 8%, transparent);
|
background: color-mix(in srgb, #1f7a8c 8%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-sentence-list {
|
.chatpapers-lecture-para-detail .chatpapers-lecture-sentence-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-sentence-chip {
|
.chatpapers-lecture-para-detail .chatpapers-lecture-sentence-chip {
|
||||||
|
display: block;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -1088,15 +1135,24 @@ collapsible-section[open] > :not(.head) .chatpapers-lecture-root {
|
|||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
white-space: normal;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-sentence-chip.is-active {
|
.chatpapers-lecture-para-detail .chatpapers-lecture-sentence-chip.is-active {
|
||||||
background: color-mix(in srgb, #1f7a8c 12%, transparent);
|
background: color-mix(in srgb, #1f7a8c 12%, transparent);
|
||||||
border-color: color-mix(in srgb, #1f7a8c 40%, transparent);
|
border-color: color-mix(in srgb, #1f7a8c 40%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chatpapers-lecture-selection-explain .chatpapers-lecture-para-original.is-active-sentence {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
border-left: 3px solid #1f7a8c;
|
||||||
|
padding: 6px 8px;
|
||||||
|
background: color-mix(in srgb, #1f7a8c 8%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-pdf-sync-hint {
|
.chatpapers-lecture-pdf-sync-hint {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
@@ -1105,9 +1161,7 @@ collapsible-section[open] > :not(.head) .chatpapers-lecture-root {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-para-detail {
|
.chatpapers-lecture-para-detail {
|
||||||
display: flex;
|
display: block;
|
||||||
flex-direction: column;
|
|
||||||
gap: 6px;
|
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: color-mix(in srgb, #1f7a8c 5%, transparent);
|
background: color-mix(in srgb, #1f7a8c 5%, transparent);
|
||||||
@@ -1139,15 +1193,25 @@ collapsible-section[open] > :not(.head) .chatpapers-lecture-root {
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
overflow-x: hidden;
|
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chatpapers-lecture-beat-detail .chatpapers-lecture-beat-script {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
max-width: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.55;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-para-detail .chatpapers-lecture-para-original-label,
|
.chatpapers-lecture-para-detail .chatpapers-lecture-para-original-label,
|
||||||
.chatpapers-lecture-para-detail .chatpapers-lecture-para-translation-label,
|
.chatpapers-lecture-para-detail .chatpapers-lecture-para-translation-label,
|
||||||
.chatpapers-lecture-para-detail .chatpapers-lecture-para-context-label {
|
.chatpapers-lecture-para-detail .chatpapers-lecture-para-context-label {
|
||||||
|
display: block;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1160,8 +1224,15 @@ collapsible-section[open] > :not(.head) .chatpapers-lecture-root {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-para-play-btn {
|
.chatpapers-lecture-para-play-btn {
|
||||||
align-self: flex-start;
|
display: inline-flex;
|
||||||
margin-bottom: 2px;
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatpapers-lecture-beat-detail-meta {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
opacity: 0.78;
|
||||||
|
line-height: 1.35;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-selection-explain {
|
.chatpapers-lecture-selection-explain {
|
||||||
@@ -1208,20 +1279,26 @@ collapsible-section[open] > :not(.head) .chatpapers-lecture-root {
|
|||||||
.chatpapers-lecture-para-original-label,
|
.chatpapers-lecture-para-original-label,
|
||||||
.chatpapers-lecture-para-translation-label,
|
.chatpapers-lecture-para-translation-label,
|
||||||
.chatpapers-lecture-para-context-label {
|
.chatpapers-lecture-para-context-label {
|
||||||
|
display: block;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
margin-top: 4px;
|
margin-top: 8px;
|
||||||
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-para-original {
|
.chatpapers-lecture-para-original {
|
||||||
|
display: block;
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-para-translation {
|
.chatpapers-lecture-para-translation {
|
||||||
|
display: block;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-para-context {
|
.chatpapers-lecture-para-context {
|
||||||
@@ -1337,33 +1414,7 @@ collapsible-section[open] > :not(.head) .chatpapers-lecture-root {
|
|||||||
opacity: 0.55;
|
opacity: 0.55;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chatpapers-lecture-beat-line {
|
/* beat-line / beat-preview 规则见上方 .chatpapers-lecture-beat-list 作用域 */
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
min-width: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chatpapers-lecture-beat-label {
|
|
||||||
flex-shrink: 0;
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.3;
|
|
||||||
opacity: 0.72;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chatpapers-lecture-beat-preview {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
min-width: 0;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1.4;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chatpapers-lecture-beat-status {
|
.chatpapers-lecture-beat-status {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ lecture-status-ready-phase1 = Preparation done (Phase 1: summary ready)
|
|||||||
lecture-status-ready-step1 = Ready: { $count } segments — tap a segment or press Play
|
lecture-status-ready-step1 = Ready: { $count } segments — tap a segment or press Play
|
||||||
lecture-status-failed = Preparation incomplete
|
lecture-status-failed = Preparation incomplete
|
||||||
lecture-beat-list-title = Overview lecture
|
lecture-beat-list-title = Overview lecture
|
||||||
|
lecture-beat-list-hint = Click a segment for details; click ▶ to play
|
||||||
|
lecture-beat-detail-empty = Select a segment above to view the full script
|
||||||
|
lecture-beat-label = Segment { $n }
|
||||||
lecture-play-start = Play
|
lecture-play-start = Play
|
||||||
lecture-play-pause = Pause
|
lecture-play-pause = Pause
|
||||||
lecture-play-next = Next
|
lecture-play-next = Next
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ lecture-status-ready-phase1 = 备课完成(Phase 1:摘要已生成)
|
|||||||
lecture-status-ready-step1 = 备课完成:{ $count } 段讲解可播放,点击下方段落或播放按钮开始听课
|
lecture-status-ready-step1 = 备课完成:{ $count } 段讲解可播放,点击下方段落或播放按钮开始听课
|
||||||
lecture-status-failed = 备课未完成,请重试或检查 LLM 设置
|
lecture-status-failed = 备课未完成,请重试或检查 LLM 设置
|
||||||
lecture-beat-list-title = 整体讲解
|
lecture-beat-list-title = 整体讲解
|
||||||
|
lecture-beat-list-hint = 点击讲解段查看详情,点击 ▶ 开始朗读
|
||||||
|
lecture-beat-detail-empty = 点击上方讲解段查看完整讲稿
|
||||||
|
lecture-beat-label = 讲解 { $n }
|
||||||
lecture-play-start = 播放
|
lecture-play-start = 播放
|
||||||
lecture-play-pause = 暂停
|
lecture-play-pause = 暂停
|
||||||
lecture-play-next = 下一段
|
lecture-play-next = 下一段
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "zotero-plugin serve",
|
"start": "zotero-plugin serve",
|
||||||
"build": "zotero-plugin build && tsc --noEmit",
|
"build": "zotero-plugin build && tsc --noEmit",
|
||||||
|
"clean": "rm -rf .scaffold/build",
|
||||||
|
"rebuild": "npm run clean && npm run build",
|
||||||
"lint:check": "prettier --check . && eslint .",
|
"lint:check": "prettier --check . && eslint .",
|
||||||
"lint:fix": "prettier --write . && eslint . --fix",
|
"lint:fix": "prettier --write . && eslint . --fix",
|
||||||
"release": "zotero-plugin release",
|
"release": "zotero-plugin release",
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ export class LecturePaneView {
|
|||||||
private playMode: "overview" | "paragraph" = "paragraph";
|
private playMode: "overview" | "paragraph" = "paragraph";
|
||||||
private readGranularity: ReadGranularity = "paragraph";
|
private readGranularity: ReadGranularity = "paragraph";
|
||||||
private activeBeatId?: string;
|
private activeBeatId?: string;
|
||||||
|
private selectedBeatId?: string;
|
||||||
|
private cachedBeats: StoredBeat[] = [];
|
||||||
private activeParagraphId?: string;
|
private activeParagraphId?: string;
|
||||||
private activeSentenceId?: string;
|
private activeSentenceId?: string;
|
||||||
private selectedParagraphId?: string;
|
private selectedParagraphId?: string;
|
||||||
@@ -209,10 +211,7 @@ export class LecturePaneView {
|
|||||||
);
|
);
|
||||||
this.paraListHintEl.hidden = true;
|
this.paraListHintEl.hidden = true;
|
||||||
this.beatListEl = this.el("div", "chatpapers-lecture-beat-list chatpapers-lecture-scroll-y");
|
this.beatListEl = this.el("div", "chatpapers-lecture-beat-list chatpapers-lecture-scroll-y");
|
||||||
this.paragraphDetailEl = this.el(
|
this.paragraphDetailEl = this.el("div", "chatpapers-lecture-para-detail");
|
||||||
"div",
|
|
||||||
"chatpapers-lecture-para-detail chatpapers-lecture-scroll-y",
|
|
||||||
);
|
|
||||||
this.selectionExplainEl = this.el("div", "chatpapers-lecture-selection-explain");
|
this.selectionExplainEl = this.el("div", "chatpapers-lecture-selection-explain");
|
||||||
this.selectionExplainEl.hidden = true;
|
this.selectionExplainEl.hidden = true;
|
||||||
|
|
||||||
@@ -551,6 +550,7 @@ export class LecturePaneView {
|
|||||||
? getString("lecture-sentence-list-title")
|
? getString("lecture-sentence-list-title")
|
||||||
: getString("lecture-paragraph-list-title");
|
: getString("lecture-paragraph-list-title");
|
||||||
this.paraListHintEl.hidden = false;
|
this.paraListHintEl.hidden = false;
|
||||||
|
this.paraListHintEl.textContent = getString("lecture-para-list-hint");
|
||||||
this.renderParagraphList(paragraphs);
|
this.renderParagraphList(paragraphs);
|
||||||
this.renderParagraphDetail(
|
this.renderParagraphDetail(
|
||||||
paragraphs,
|
paragraphs,
|
||||||
@@ -598,11 +598,13 @@ export class LecturePaneView {
|
|||||||
this.granularityTabsEl.classList.add("is-visible");
|
this.granularityTabsEl.classList.add("is-visible");
|
||||||
} else if (hasBeats) {
|
} else if (hasBeats) {
|
||||||
this.granularityTabsEl.classList.remove("is-visible");
|
this.granularityTabsEl.classList.remove("is-visible");
|
||||||
this.paraListHintEl.hidden = true;
|
this.paraListHintEl.hidden = false;
|
||||||
|
this.paraListHintEl.textContent = getString("lecture-beat-list-hint");
|
||||||
this.playerTitleEl.textContent = getString("lecture-beat-list-title");
|
this.playerTitleEl.textContent = getString("lecture-beat-list-title");
|
||||||
this.beatListEl.hidden = false;
|
this.beatListEl.hidden = false;
|
||||||
this.paragraphDetailEl.hidden = true;
|
this.cachedBeats = beats;
|
||||||
this.renderBeatList(beats);
|
this.renderBeatList(beats);
|
||||||
|
this.renderBeatDetail(beats, this.selectedBeatId ?? this.activeBeatId);
|
||||||
|
|
||||||
if (!this.player) {
|
if (!this.player) {
|
||||||
this.player = createPlayLecture({
|
this.player = createPlayLecture({
|
||||||
@@ -610,7 +612,9 @@ export class LecturePaneView {
|
|||||||
beats,
|
beats,
|
||||||
onBeatChange: (id) => {
|
onBeatChange: (id) => {
|
||||||
this.activeBeatId = id;
|
this.activeBeatId = id;
|
||||||
this.highlightBeat(id);
|
if (id) this.selectedBeatId = id;
|
||||||
|
this.renderBeatList(this.cachedBeats);
|
||||||
|
this.renderBeatDetail(this.cachedBeats, id);
|
||||||
},
|
},
|
||||||
onPlayingChange: (playing) => {
|
onPlayingChange: (playing) => {
|
||||||
this.playBtn.hidden = playing;
|
this.playBtn.hidden = playing;
|
||||||
@@ -843,7 +847,10 @@ export class LecturePaneView {
|
|||||||
if (!para) {
|
if (!para) {
|
||||||
this.paragraphDetailEl.hidden = false;
|
this.paragraphDetailEl.hidden = false;
|
||||||
this.paragraphDetailEl.classList.add("is-empty");
|
this.paragraphDetailEl.classList.add("is-empty");
|
||||||
this.paragraphDetailEl.classList.remove("chatpapers-lecture-scroll-y");
|
this.paragraphDetailEl.classList.remove(
|
||||||
|
"chatpapers-lecture-scroll-y",
|
||||||
|
"chatpapers-lecture-beat-detail",
|
||||||
|
);
|
||||||
this.paragraphDetailEl.append(
|
this.paragraphDetailEl.append(
|
||||||
this.el(
|
this.el(
|
||||||
"div",
|
"div",
|
||||||
@@ -854,7 +861,7 @@ export class LecturePaneView {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.paragraphDetailEl.hidden = false;
|
this.paragraphDetailEl.hidden = false;
|
||||||
this.paragraphDetailEl.classList.remove("is-empty");
|
this.paragraphDetailEl.classList.remove("is-empty", "chatpapers-lecture-beat-detail");
|
||||||
this.paragraphDetailEl.classList.add("chatpapers-lecture-scroll-y");
|
this.paragraphDetailEl.classList.add("chatpapers-lecture-scroll-y");
|
||||||
|
|
||||||
const sentence = sentenceId
|
const sentence = sentenceId
|
||||||
@@ -896,7 +903,11 @@ export class LecturePaneView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const originalText = sentence?.text ?? para.originalText;
|
const originalText = sentence?.text ?? para.originalText;
|
||||||
const translationText = sentence?.translation ?? para.translation;
|
const translationText = (
|
||||||
|
sentence?.translation ||
|
||||||
|
(!sentence ? para.translation : "") ||
|
||||||
|
""
|
||||||
|
).trim();
|
||||||
|
|
||||||
this.paragraphDetailEl.append(
|
this.paragraphDetailEl.append(
|
||||||
this.el("div", "chatpapers-lecture-para-original-label", getString("lecture-para-original")),
|
this.el("div", "chatpapers-lecture-para-original-label", getString("lecture-para-original")),
|
||||||
@@ -905,11 +916,20 @@ export class LecturePaneView {
|
|||||||
`chatpapers-lecture-para-original${sentence ? " is-active-sentence" : ""}`,
|
`chatpapers-lecture-para-original${sentence ? " is-active-sentence" : ""}`,
|
||||||
originalText,
|
originalText,
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (translationText) {
|
||||||
|
this.paragraphDetailEl.append(
|
||||||
this.el("div", "chatpapers-lecture-para-translation-label", getString("lecture-para-translation")),
|
this.el("div", "chatpapers-lecture-para-translation-label", getString("lecture-para-translation")),
|
||||||
this.el("div", "chatpapers-lecture-para-translation", translationText),
|
this.el("div", "chatpapers-lecture-para-translation", translationText),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (sentence && (para.sentences?.length ?? 0) > 1) {
|
if (
|
||||||
|
sentence &&
|
||||||
|
this.readGranularity !== "sentence" &&
|
||||||
|
(para.sentences?.length ?? 0) > 1
|
||||||
|
) {
|
||||||
const sentenceList = this.el("div", "chatpapers-lecture-sentence-list");
|
const sentenceList = this.el("div", "chatpapers-lecture-sentence-list");
|
||||||
for (const s of para.sentences ?? []) {
|
for (const s of para.sentences ?? []) {
|
||||||
const item = this.doc.createElement("button");
|
const item = this.doc.createElement("button");
|
||||||
@@ -1097,30 +1117,68 @@ export class LecturePaneView {
|
|||||||
private renderBeatList(beats: StoredBeat[]): void {
|
private renderBeatList(beats: StoredBeat[]): void {
|
||||||
this.beatListEl.replaceChildren();
|
this.beatListEl.replaceChildren();
|
||||||
for (const beat of beats) {
|
for (const beat of beats) {
|
||||||
const row = this.doc.createElement("button") as HTMLButtonElement;
|
this.beatListEl.append(this.makeBeatRow(beats, beat));
|
||||||
row.type = "button";
|
|
||||||
row.className = "chatpapers-lecture-beat-item";
|
|
||||||
row.dataset.beatId = beat.id;
|
|
||||||
if (beat.id === this.activeBeatId) {
|
|
||||||
row.classList.add("is-active");
|
|
||||||
}
|
}
|
||||||
if (beat.ttsStatus !== "ready") {
|
|
||||||
row.classList.add("is-pending");
|
|
||||||
row.disabled = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const meta = this.el("div", "chatpapers-lecture-beat-meta");
|
private isBeatSelected(beatId: string): boolean {
|
||||||
meta.append(
|
return this.selectedBeatId === beatId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isBeatPlaying(beatId: string): boolean {
|
||||||
|
return this.activeBeatId === beatId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private selectBeat(beats: StoredBeat[], beatId: string): void {
|
||||||
|
this.selectedBeatId = beatId;
|
||||||
|
this.renderBeatList(beats);
|
||||||
|
this.renderBeatDetail(beats, beatId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private playBeat(beat: StoredBeat): void {
|
||||||
|
void this.player?.jumpToBeatId(beat.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private makeBeatPlayButton(beat: StoredBeat): HTMLButtonElement {
|
||||||
|
const playBtn = this.doc.createElement("button");
|
||||||
|
playBtn.type = "button";
|
||||||
|
playBtn.className = "chatpapers-lecture-beat-play";
|
||||||
|
playBtn.title = getString("lecture-para-play");
|
||||||
|
playBtn.setAttribute("aria-label", getString("lecture-para-play"));
|
||||||
|
playBtn.append(
|
||||||
|
createLucideIcon(this.doc, Play, {
|
||||||
|
size: 14,
|
||||||
|
className: "chatpapers-lecture-btn-icon",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
playBtn.disabled = beat.ttsStatus !== "ready";
|
||||||
|
playBtn.addEventListener("click", (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
this.playBeat(beat);
|
||||||
|
});
|
||||||
|
return playBtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private makeBeatRow(beats: StoredBeat[], beat: StoredBeat): HTMLElement {
|
||||||
|
const row = this.el("div", "chatpapers-lecture-beat-item");
|
||||||
|
row.dataset.beatId = beat.id;
|
||||||
|
if (this.isBeatSelected(beat.id)) row.classList.add("is-selected");
|
||||||
|
if (this.isBeatPlaying(beat.id)) row.classList.add("is-active");
|
||||||
|
if (beat.ttsStatus !== "ready") row.classList.add("is-pending");
|
||||||
|
|
||||||
|
const main = this.doc.createElement("button");
|
||||||
|
main.type = "button";
|
||||||
|
main.className = "chatpapers-lecture-beat-main";
|
||||||
|
|
||||||
|
const preview = beat.title?.trim() || beat.script;
|
||||||
|
const line = this.el("div", "chatpapers-lecture-beat-line");
|
||||||
|
line.append(
|
||||||
this.el(
|
this.el(
|
||||||
"span",
|
"span",
|
||||||
"chatpapers-lecture-beat-type",
|
"chatpapers-lecture-beat-label",
|
||||||
BEAT_TYPE_LABELS[beat.type] || beat.type,
|
getString("lecture-beat-label", { args: { n: beat.orderIndex + 1 } }),
|
||||||
),
|
|
||||||
this.el(
|
|
||||||
"span",
|
|
||||||
"chatpapers-lecture-beat-title",
|
|
||||||
beat.title || beat.id,
|
|
||||||
),
|
),
|
||||||
|
this.el("span", "chatpapers-lecture-beat-preview", preview),
|
||||||
);
|
);
|
||||||
|
|
||||||
const status = this.el("span", "chatpapers-lecture-beat-status");
|
const status = this.el("span", "chatpapers-lecture-beat-status");
|
||||||
@@ -1132,22 +1190,70 @@ export class LecturePaneView {
|
|||||||
status.textContent = getString("lecture-beat-tts-pending");
|
status.textContent = getString("lecture-beat-tts-pending");
|
||||||
}
|
}
|
||||||
|
|
||||||
row.append(meta, status);
|
main.append(line, status);
|
||||||
row.addEventListener("click", () => {
|
main.title = preview;
|
||||||
void this.player?.jumpToBeatId(beat.id);
|
main.addEventListener("click", () => {
|
||||||
|
this.selectBeat(beats, beat.id);
|
||||||
});
|
});
|
||||||
this.beatListEl.append(row);
|
|
||||||
}
|
row.append(main, this.makeBeatPlayButton(beat));
|
||||||
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
private highlightBeat(beatId?: string): void {
|
private renderBeatDetail(beats: StoredBeat[], beatId?: string): void {
|
||||||
this.activeBeatId = beatId;
|
const beat = beatId ? beats.find((b) => b.id === beatId) : undefined;
|
||||||
for (const node of this.beatListEl.querySelectorAll(
|
this.paragraphDetailEl.replaceChildren();
|
||||||
".chatpapers-lecture-beat-item",
|
if (!beat) {
|
||||||
)) {
|
this.paragraphDetailEl.hidden = false;
|
||||||
const el = node as HTMLElement;
|
this.paragraphDetailEl.classList.add("is-empty");
|
||||||
el.classList.toggle("is-active", el.dataset.beatId === beatId);
|
this.paragraphDetailEl.classList.remove(
|
||||||
|
"chatpapers-lecture-scroll-y",
|
||||||
|
"chatpapers-lecture-beat-detail",
|
||||||
|
);
|
||||||
|
this.paragraphDetailEl.append(
|
||||||
|
this.el(
|
||||||
|
"div",
|
||||||
|
"chatpapers-lecture-para-detail-empty",
|
||||||
|
getString("lecture-beat-detail-empty"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.paragraphDetailEl.hidden = false;
|
||||||
|
this.paragraphDetailEl.classList.remove("is-empty");
|
||||||
|
this.paragraphDetailEl.classList.add(
|
||||||
|
"chatpapers-lecture-scroll-y",
|
||||||
|
"chatpapers-lecture-beat-detail",
|
||||||
|
);
|
||||||
|
|
||||||
|
const playBtn = this.doc.createElement("button");
|
||||||
|
playBtn.type = "button";
|
||||||
|
playBtn.className =
|
||||||
|
"chatpapers-lecture-secondary chatpapers-lecture-para-play-btn";
|
||||||
|
playBtn.append(
|
||||||
|
createLucideIcon(this.doc, Play, {
|
||||||
|
size: 14,
|
||||||
|
className: "chatpapers-lecture-btn-icon",
|
||||||
|
}),
|
||||||
|
this.doc.createTextNode(getString("lecture-para-play")),
|
||||||
|
);
|
||||||
|
playBtn.disabled = beat.ttsStatus !== "ready";
|
||||||
|
playBtn.addEventListener("click", () => {
|
||||||
|
this.playBeat(beat);
|
||||||
|
});
|
||||||
|
this.paragraphDetailEl.append(playBtn);
|
||||||
|
|
||||||
|
const typeLabel = BEAT_TYPE_LABELS[beat.type] || beat.type;
|
||||||
|
const title = beat.title?.trim();
|
||||||
|
this.paragraphDetailEl.append(
|
||||||
|
this.el(
|
||||||
|
"div",
|
||||||
|
"chatpapers-lecture-beat-detail-meta",
|
||||||
|
title ? `${typeLabel} · ${title}` : typeLabel,
|
||||||
|
),
|
||||||
|
this.el("div", "chatpapers-lecture-beat-script", beat.script),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async statusMessage(
|
private async statusMessage(
|
||||||
|
|||||||
@@ -88,14 +88,27 @@ export function registerPrefs() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureChatPapersStyles(doc: Document) {
|
export function ensureChatPapersStyles(doc: Document): void {
|
||||||
const id = "chatpapers-styles";
|
const id = "chatpapers-styles";
|
||||||
if (doc.getElementById(id)) return;
|
const base = `chrome://${config.addonRef}/content/chatpapers.css`;
|
||||||
|
const href =
|
||||||
|
typeof __env__ !== "undefined" && __env__ === "development"
|
||||||
|
? `${base}?v=${Date.now()}`
|
||||||
|
: base;
|
||||||
|
|
||||||
|
const existing = doc.getElementById(id) as HTMLLinkElement | null;
|
||||||
|
if (existing) {
|
||||||
|
if (typeof __env__ !== "undefined" && __env__ === "development") {
|
||||||
|
existing.href = href;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const link = doc.createElement("link");
|
const link = doc.createElement("link");
|
||||||
link.id = id;
|
link.id = id;
|
||||||
link.rel = "stylesheet";
|
link.rel = "stylesheet";
|
||||||
link.type = "text/css";
|
link.type = "text/css";
|
||||||
link.href = `chrome://${config.addonRef}/content/chatpapers.css`;
|
link.href = href;
|
||||||
doc.documentElement?.appendChild(link);
|
doc.documentElement?.appendChild(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+3
@@ -44,6 +44,9 @@ export type FluentMessageId =
|
|||||||
| 'itemmenu-compare'
|
| 'itemmenu-compare'
|
||||||
| 'itemmenu-label'
|
| 'itemmenu-label'
|
||||||
| 'lecture-attach-error'
|
| 'lecture-attach-error'
|
||||||
|
| 'lecture-beat-detail-empty'
|
||||||
|
| 'lecture-beat-label'
|
||||||
|
| 'lecture-beat-list-hint'
|
||||||
| 'lecture-beat-list-title'
|
| 'lecture-beat-list-title'
|
||||||
| 'lecture-beat-tts-failed'
|
| 'lecture-beat-tts-failed'
|
||||||
| 'lecture-beat-tts-pending'
|
| 'lecture-beat-tts-pending'
|
||||||
|
|||||||
Reference in New Issue
Block a user