代码: 全选
Here are the specific sections of the code that need to be modified to implement your requested changes for the `mini` mode. All code and comments are in English.
### 1. Update `constructor()`
Replace the `miniBgOpacity` and `miniTextOpacity` properties with the new `miniCommentMaxH` property.
```javascript
// In constructor()
// Remove these:
// this.miniBgOpacity = 0.6;
// this.miniTextOpacity = 1;
// Add this:
this.miniCommentMaxH = 120;
this.miniFontSize = 14;
```
### 2. Update `injectCSS()`
Modify the CSS rules for the `mini` mode. Replace the opacity variables, update the branch and comment containers, and remove the unused dropdown styles.
```javascript
// In injectCSS() within the `if (this.mode === 'single' || this.mode === 'mini') { ... }` block
afterContainerCSS = `
/* Use Container Queries instead of Media Queries */
@container chess-container (max-width: 767px) {
.ejcees-inner { flex-direction: column; }
.ejceesctrl { flex: 1 0 272px; min-height: 272px; }
.ejceessvg { width: 100%; height: auto; max-height: calc(100cqw * 480 / 432); }
.ejceespb { width: 100%; height: auto; max-height: 100%; }
.ejceestool, .ejceesstep, .ejceesoutput { padding: 0 7px; }
.ejceesstep { gap: 7px; }
.ejceesrecord { width: 200px; font-size: 12px; }
.ejceesrcdstep .ejceesrcdstepcontent { margin-left: 24px; }
.branch-marker { margin-left: 1px; }
.exp-fmt-outer { display: grid; grid-template-columns: repeat(2, 1fr); gap: 5px; }
.exp-fmt-btn { padding: 5px; cursor: pointer; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}
@container chess-container (min-width: 768px) {
.ejcees-inner { flex-direction: row; }
.ejceesctrl { flex: 1 0 414px; min-width: 414px; }
.ejceessvg { height: 100%; width: auto; max-width: calc(100cqh * 432 / 480); }
.ejceespb { height: 100%; width: auto; max-width: 100%; }
.ejceestool, .ejceesstep, .ejceesoutput { padding: 0 12px; }
.ejceesstep { gap: 12px; }
.ejceesrecord { width: 268px; font-size: 16px; }
}
/* mini specific elements */
.ejcees-inner.mini-mode {
--mini-fz: ${this.miniFontSize}px;
--mini-comment-max-h: ${this.miniCommentMaxH}px;
}
.mini-output-settings {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%237c7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>');
background-repeat: no-repeat;
background-position: center bottom;
background-size: 16px 16px;
cursor: pointer;
align-items: start;
overflow: visible;
font-size: 14px;
}
.mini-settings-panel {
position: absolute;
top: 8px;
right: 8px;
background-color: rgba(0, 0, 0, 0.85); /* Hardcoded solid dark background */
color: #fff;
padding: 12px;
border-radius: 6px;
z-index: 100;
display: flex;
flex-direction: column;
gap: 10px;
font-size: var(--mini-fz);
min-width: 240px;
}
.mini-settings-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.mini-settings-label {
flex: 0 0 100px;
white-space: nowrap;
}
.mini-settings-value {
flex: 0 0 30px;
text-align: right;
font-variant-numeric: tabular-nums;
color: #aaa;
}
.mini-settings-panel input[type="range"] {
flex: 1;
width: 100%;
}
.mini-branch-container {
display: none;
text-align: left;
padding: 8px;
font-size: var(--mini-fz);
}
.mini-branch-container .branch-move-link {
display: inline-block;
color: #eee;
padding: 4px 8px;
margin: 2px 4px 2px 0;
cursor: pointer;
border: 1px dashed #ccc;
border-radius: 4px;
}
.mini-branch-container .branch-move-link:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.mini-branch-container .branch-move-link.active {
font-weight: bold;
border: 1px solid #fff;
background-color: rgba(255, 255, 255, 0.2);
}
.mini-comment {
display: none;
color: #eee;
padding: 8px;
font-size: var(--mini-fz);
box-sizing: border-box;
white-space: pre-wrap;
word-break: break-all;
max-height: var(--mini-comment-max-h);
overflow-y: auto;
}
/* Button styling matching the dark theme */
.mini-exp-txt {
background-color: rgba(255, 255, 255, 0.2);
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.3);
padding: 4px 12px;
border-radius: 4px;
cursor: pointer;
font-size: var(--mini-fz);
transition: background-color 0.2s;
}
.mini-exp-txt:hover {
background-color: rgba(255, 255, 255, 0.3);
}
/* Full-screen overlay panel */
.mini-exp-txt-panel {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.85);
z-index: 200;
display: flex;
flex-direction: column;
}
/* Textarea styling */
.mini-exp-txt-textarea:focus,
.mini-exp-txt-textarea {
width: 100%;
height: 100%;
background: transparent;
color: #eee;
border: none;
padding: 40px 15px 15px 15px;
box-sizing: border-box;
font-size: 14px;
font-family: monospace;
resize: none;
outline: none;
}
/* Close button positioning and styling */
.mini-exp-txt-close {
position: absolute;
top: 5px;
right: 5px;
width: 36px;
height: 36px;
background: none;
border: none;
cursor: pointer;
color: white;
display: flex;
align-items: center;
justify-content: center;
z-index: 210;
}
.mini-exp-txt-close:hover {
color: #ff4444;
}
.ejceessvg > object {
width: 100%;
height: auto;
pointer-events: none;
}`;
```
### 3. Update `renderDOM()`
Move the branch and comment containers out of `.ejceessvg` and place them after `.ejceesctrl`. Update the `.mini-settings-panel` inputs.
```javascript
// In renderDOM(), if (this.mode === 'mini') { ... } block
if (this.mode === 'mini') {
this.container.innerHTML = `
<div class="ejcees-inner mini-mode" tabindex="-1" style="--mini-fz: ${this.miniFontSize}px; --mini-comment-max-h: ${this.miniCommentMaxH}px;">
<div class="ejceessvg" style="position: relative;" tabindex="-1">
<div id="mini-settings-panel" class="mini-settings-panel" style="display: none;">
<div class="mini-settings-row">
<span class="mini-settings-label">Max Height:</span>
<span class="mini-settings-value" id="val-comment-h">${this.miniCommentMaxH}</span>
<input type="range" id="mini-comment-h-slider" min="60" max="360" step="10" value="${this.miniCommentMaxH}">
</div>
<div class="mini-settings-row">
<span class="mini-settings-label">Font Size (px):</span>
<span class="mini-settings-value" id="val-fz">${this.miniFontSize}</span>
<input type="range" id="mini-fz-slider" min="12" max="24" step="1" value="${this.miniFontSize}">
</div>
<div class="mini-settings-row">
<span class="mini-settings-label">Interval (s):</span>
<span class="mini-settings-value" id="val-interval">${this.moveInterval}</span>
<input type="range" id="mini-interval-slider" min="1" max="4" step="0.2" value="${this.moveInterval}">
</div>
<div class="mini-settings-row">
<span class="mini-settings-label">Speed (s):</span>
<span class="mini-settings-value" id="val-speed">${this.moveSpeed}</span>
<input type="range" id="mini-speed-slider" min="0.1" max="2" step="0.1" value="${this.moveSpeed}">
</div>
<div style="text-align: center;">
<button type="button" class="mini-exp-txt" id="mini-exp-btn">Export Text</button>
</div>
</div>
</div>
<div class="ejceesctrl" style="flex: 0 0 auto; min-height: unset; height: 48px;">
<div class="ejceesstep">
<div class="ejceesoutput mini-output-settings">0/0</div>
<div class="ejceesstepminus">-</div>
<input type="range" class="ejceesstepdrop" min="0" max="0" value="0" />
<div class="ejceesstepplus">+</div>
<div class="note-btn" id="btn-autoplay" title="Auto Play" style="width: 36px; height: 36px; cursor: pointer; display: flex; align-items: center; justify-content: center; background-color: transparent;">
<svg viewBox="0 0 24 24" style="width: 20px; height: 20px; fill: #ccc;"><path d="M8 5v14l11-7z"/></svg>
</div>
</div>
</div>
<div id="mini-branch-container" class="mini-branch-container"></div>
<div id="mini-comment-container" class="mini-comment"></div>
<input type="file" id="file-input" style="display: none" />
</div>`;
}
```
### 4. Update `bindEvents()`
Refactor the event bindings for sliders, outside clicks, and the export text panel.
```javascript
// In bindEvents(), if (this.mode === 'mini') { ... } block
if (this.mode === 'mini') {
// -- Bind Settings UI --
const outputEl = this.container.querySelector('.ejceesoutput');
const settingsPanel = this.container.querySelector('#mini-settings-panel');
const innerWrapper = this.container.querySelector('.ejcees-inner');
if (outputEl && settingsPanel) {
outputEl.addEventListener('click', (e) => {
e.stopPropagation(); // Stop propagation to allow outside click logic
settingsPanel.style.display = settingsPanel.style.display === 'none' ? 'flex' : 'none';
});
}
// Stop clicks inside the settings panel from closing it
if (settingsPanel) {
settingsPanel.addEventListener('click', (e) => e.stopPropagation());
}
// Close settings panel when clicking outside
this.container.addEventListener('click', () => {
if (settingsPanel && settingsPanel.style.display !== 'none') {
settingsPanel.style.display = 'none';
}
});
const commentHSlider = this.container.querySelector('#mini-comment-h-slider');
const commentHVal = this.container.querySelector('#val-comment-h');
if (commentHSlider && commentHVal) {
commentHSlider.addEventListener('input', e => {
this.miniCommentMaxH = e.target.value;
commentHVal.textContent = this.miniCommentMaxH;
innerWrapper.style.setProperty('--mini-comment-max-h', this.miniCommentMaxH + 'px');
});
}
const fzSlider = this.container.querySelector('#mini-fz-slider');
const fzVal = this.container.querySelector('#val-fz');
if (fzSlider && fzVal) {
fzSlider.addEventListener('input', e => {
this.miniFontSize = e.target.value;
fzVal.textContent = this.miniFontSize;
innerWrapper.style.setProperty('--mini-fz', this.miniFontSize + 'px');
});
}
const intervalSlider = this.container.querySelector('#mini-interval-slider');
const intervalVal = this.container.querySelector('#val-interval');
if (intervalSlider && intervalVal) {
intervalSlider.addEventListener('input', e => {
this.moveInterval = parseFloat(e.target.value);
intervalVal.textContent = this.moveInterval;
});
}
const speedSlider = this.container.querySelector('#mini-speed-slider');
const speedVal = this.container.querySelector('#val-speed');
if (speedSlider && speedVal) {
speedSlider.addEventListener('input', e => {
this.moveSpeed = parseFloat(e.target.value);
speedVal.textContent = this.moveSpeed;
});
}
const exportBtn = this.container.querySelector('#mini-exp-btn');
if (exportBtn) {
exportBtn.addEventListener('click', () => {
// Hide branch and comment containers
const branchContainer = this.container.querySelector('#mini-branch-container');
const commentContainer = this.container.querySelector('#mini-comment-container');
if (branchContainer) branchContainer.style.display = 'none';
if (commentContainer) commentContainer.style.display = 'none';
// 1. Create the panel element
const panel = document.createElement('div');
panel.className = 'mini-exp-txt-panel';
// 2. Create the Close Button (SVG icon)
const closeBtn = document.createElement('button');
closeBtn.className = 'mini-exp-txt-close';
closeBtn.innerHTML = `
<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
`;
// 3. Create the Textarea
const textarea = document.createElement('textarea');
textarea.className = 'mini-exp-txt-textarea';
// Use textContent from the container as requested
textarea.value = this.initialTextContent;
// 4. Close logic: Remove the panel from DOM and restore UI
closeBtn.onclick = () => {
panel.remove();
this.renderRecordUI();
this.renderNoteUI();
};
// 5. Assemble and append
panel.appendChild(closeBtn);
panel.appendChild(textarea);
this.container.appendChild(panel);
// Hide settings panel
if (settingsPanel) settingsPanel.style.display = 'none';
// 6. Focus and Select text automatically
textarea.focus();
textarea.select();
});
}
```
### 5. Update `renderRecordUI()`
Rewrite the `this.mode === 'mini'` block to render inline `.branch-move-link` buttons and handle `.mini-exp-txt-panel` blocking state.
```javascript
// Inside renderRecordUI()
renderRecordUI() {
if (this.mode === 'mini') {
const totalDepth = this.getPathDepth(this.historyFEN, this.currentBranch);
this.stepSlider.max = Math.max(0, totalDepth - 1);
const branchContainer = this.container.querySelector('#mini-branch-container');
const parentNode = this.getNodeAtStep(this.currentStepIndex - 1);
branchContainer.innerHTML = ''; // Clear existing contents
// Check if export panel is active
const isExportPanelActive = this.container.querySelector('.mini-exp-txt-panel') !== null;
if (!isExportPanelActive && parentNode && parentNode.v && parentNode.v.length > 1) {
branchContainer.style.display = 'block';
let forkIndex = -1;
let tempNode = this.historyFEN;
for (let j = 0; j < this.currentStepIndex - 1; j++) {
if (tempNode.v && tempNode.v.length > 1) forkIndex++;
const choice = tempNode.v && tempNode.v.length > 1 ? this.currentBranch[forkIndex] || 0 : 0;
tempNode = tempNode.v[choice];
}
forkIndex++;
// Add inline branch links
parentNode.v.forEach((child, idx) => {
const moveLink = document.createElement('div');
moveLink.className = 'branch-move-link';
if (this.currentBranch[forkIndex] === idx) {
moveLink.classList.add('active');
}
moveLink.innerText = this.NotationConverter.toChinese(child.move);
moveLink.onclick = e => {
e.stopPropagation();
this.updateBranchPath(forkIndex, idx);
this.jumpToStep(this.currentStepIndex);
this.renderRecordUI();
this.saveStateToUndo();
this.updateToolHighlights();
};
branchContainer.appendChild(moveLink);
});
} else {
branchContainer.style.display = 'none';
}
this.updateToolHighlights();
return;
}
```
### 6. Update `renderNoteUI()`
Ensure comments do not display when the export text panel is open.
```javascript
// Inside renderNoteUI()
renderNoteUI() {
if (this.mode === 'mini') {
const node = this.getNodeAtStep(this.currentStepIndex);
const commentContainer = this.container.querySelector('#mini-comment-container');
const isExportPanelActive = this.container.querySelector('.mini-exp-txt-panel') !== null;
if (!isExportPanelActive && node && node.c && node.c.trim() !== '') {
commentContainer.textContent = node.c.trim();
commentContainer.style.display = 'block';
} else {
commentContainer.style.display = 'none';
}
const autoBtnSvg = this.container.querySelector('#btn-autoplay svg');
if (autoBtnSvg) {
autoBtnSvg.innerHTML = this.isAutoPlaying
? '<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>'
: '<path d="M8 5v14l11-7z"/>';
autoBtnSvg.style.fill = this.isAutoPlaying ? '#fff' : '#ccc';
}
return;
}
```
### 7. Delete `showMiniBranchMenu()` method entirely
Because the branches are now rendered directly inside `renderRecordUI()`, you must delete the entire `showMiniBranchMenu` function from the `Ejcees` class block.