feat(slash-commands): 添加 /goto-floor 命令并实现消息高亮 - 新增 /goto-floor 命令,允许用户滚动到指定的消息索引 - 实现消息高亮功能,滚动到指定消息后进行突出显示 - 添加相关的 CSS 样式,确保高亮效果在不同浏览器中兼容

485d07b91f2bfc2e00e7de5dcbda55aa462e163f

awaae001 <3271436144@qq.com>

1 files changed, +121 -0Showing whitespace changes
public/scripts/slash-commands.js+121 -0
@@ -2130,6 +2130,127 @@ export function initDefaultSlashCommands() {
2130 `,2130 `,
2131 }));2131 }));
21322132
2133 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2134 name: 'goto-floor',
2135 aliases: ['floor', 'jump', 'scrollto'],
2136 callback: async (_, index) => {
2137 const floorIndex = Number(index);
2138
2139 // Validate input
2140 if (isNaN(floorIndex) || floorIndex < 0 || (typeof chat !== 'undefined' && floorIndex >= chat.length)) {
2141 const maxIndex = (typeof chat !== 'undefined' ? chat.length - 1 : 'unknown');
2142 toastr.warning(`Invalid message index: ${index}. Please enter a number between 0 and ${maxIndex}.`);
2143 console.warn(`WARN: Invalid message index provided for /goto-floor: ${index}. Max index: ${maxIndex}`);
2144 return '';
2145 }
2146
2147 const messageElement = document.querySelector(`[mesid="${floorIndex}"]`);
2148
2149 if (messageElement) {
2150 const headerElement = messageElement.querySelector('.mes_header') ||
2151 messageElement.querySelector('.mes_meta') ||
2152 messageElement.querySelector('.mes_name_area') ||
2153 messageElement.querySelector('.mes_name');
2154
2155 const elementToScroll = headerElement || messageElement; // Prefer header, fallback to whole message
2156 const blockPosition = headerElement ? 'center' : 'start'; // Center header, else start of message
2157
2158 elementToScroll.scrollIntoView({ behavior: 'smooth', block: blockPosition });
2159 console.log(`INFO: Scrolled ${headerElement ? 'header of' : ''} message ${floorIndex} into view (block: ${blockPosition}).`);
2160
2161 // --- Highlight with smooth animation ---
2162 messageElement.classList.add('highlight-scroll');
2163 setTimeout(() => {
2164 // Add a class to fade out, then remove the highlight class after fade
2165 messageElement.classList.add('highlight-scroll-fadeout');
2166 // Wait for fadeout transition to complete before removing the base class
2167 // Match this duration to the transition duration in CSS
2168 setTimeout(() => {
2169 messageElement.classList.remove('highlight-scroll', 'highlight-scroll-fadeout');
2170 }, 500); // Matches the 0.5s transition duration
2171 }, 1500); // Start fade out after 1.5 seconds
2172
2173 } else {
2174 toastr.warning(`Could not find element for message ${floorIndex} (using [mesid="${floorIndex}"]). It might not be rendered yet. Try scrolling up or use /chat-render all.`);
2175 console.warn(`WARN: Element not found for message index ${floorIndex} using querySelector [mesid="${floorIndex}"] in /goto-floor.`);
2176 const chatContainer = document.getElementById('chat');
2177 if (chatContainer) {
2178 chatContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
2179 }
2180 }
2181 return '';
2182 },
2183 unnamedArgumentList: [
2184 SlashCommandArgument.fromProps({
2185 description: 'The message index (0-based) to scroll to.',
2186 typeList: [ARGUMENT_TYPE.NUMBER],
2187 isRequired: true,
2188 enumProvider: commonEnumProviders.messages(),
2189 }),
2190 ],
2191 helpString: `
2192 <div>
2193 Scrolls the chat view to the specified message index. Uses the <code>[mesid]</code> attribute for locating the message element. Index starts at 0.
2194 It attempts to center the character's name/header area within the message block. Highlights the message using the theme's 'matchedText' color with a smooth animation.
2195 </div>
2196 <div>
2197 <strong>Example:</strong> <pre><code>/goto-floor 10</code></pre> Scrolls to the 11th message (mesid=10).
2198 </div>
2199 <div>
2200 Note: Due to virtual scrolling, very old messages might need loading first.
2201 </div>
2202 `,
2203 }));
2204
2205 // --- Improved CSS for highlight ---
2206 const styleId = 'goto-floor-highlight-style';
2207 if (!document.getElementById(styleId)) {
2208 const style = document.createElement('style');
2209 style.id = styleId;
2210 style.textContent = `
2211 /* Base state for elements that *can* be highlighted */
2212 /* Ensures transition applies smoothly in both directions */
2213 .mes, .mes_block {
2214 transition: background-color 0.5s ease-in-out, box-shadow 0.5s ease-in-out;
2215 /* Add position relative if not already present, needed for potential pseudo-elements */
2216 position: relative;
2217 }
2218
2219 /* --- Highlighting Style --- */
2220 .mes.highlight-scroll,
2221 .mes_block.highlight-scroll {
2222 /* Use theme color for shadow, fallback to gold */
2223 box-shadow: 0 0 10px var(--ac-style-color-matchedText, #FFD700) !important;
2224 z-index: 5; /* Ensure highlight is visually prominent */
2225 }
2226
2227 /* Modern browsers: Use color-mix for transparent background */
2228 @supports (background-color: color-mix(in srgb, white 50%, black)) {
2229 .mes.highlight-scroll,
2230 .mes_block.highlight-scroll {
2231 /* Mix theme color with transparent for background */
2232 background-color: color-mix(in srgb, var(--ac-style-color-matchedText, #FFD700) 35%, transparent) !important;
2233 }
2234 }
2235
2236 /* Fallback for older browsers: Use a fixed semi-transparent background */
2237 @supports not (background-color: color-mix(in srgb, white 50%, black)) {
2238 .mes.highlight-scroll,
2239 .mes_block.highlight-scroll {
2240 background-color: rgba(255, 215, 0, 0.35) !important; /* Fallback semi-transparent gold */
2241 }
2242 }
2243
2244 /* --- Fade-out Control --- */
2245 /* When fading out, explicitly transition back to transparent/none */
2246 .mes.highlight-scroll-fadeout,
2247 .mes_block.highlight-scroll-fadeout {
2248 background-color: transparent !important;
2249 box-shadow: none !important;
2250 }
2251 `;
2252 document.head.appendChild(style);
2253 }
2133 registerVariableCommands();2254 registerVariableCommands();
2134}2255}
21352256