fix(core): prevent ai input tip loop-play (#12600)

### TL;DR

* fix(core): prevent ai input tip loop-play

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Added an option to control whether tips in the AI chat composer scroll continuously or stop after the last tip.

- **Style**
  - Improved layout and spacing in the embedding status tooltip for better readability and alignment.

- **Refactor**
  - Updated the structure of elements in the embedding status tooltip for more consistent formatting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
yoyoyohamapi
2025-05-30 03:40:11 +00:00
parent 3c3a8bb107
commit 756847d3cb
3 changed files with 43 additions and 10 deletions

View File

@@ -34,10 +34,14 @@ export class AIChatComposerTip extends LitElement {
@property({ attribute: false })
accessor tips: TemplateResult[] = [];
@property({ attribute: false })
accessor loop: boolean = true;
private readonly _interval = 5000;
private readonly _animDuration = 500;
private _tipIntervalId: number | null = null;
private _tipListElement: HTMLDivElement | null = null;
private _currentIndex: number = 0;
override connectedCallback() {
super.connectedCallback();
@@ -76,6 +80,10 @@ export class AIChatComposerTip extends LitElement {
private _startAutoScroll() {
this._stopAutoScroll();
if (!this.loop && this._currentIndex >= this.tips.length - 1) {
return;
}
this._currentIndex = 0;
this._tipIntervalId = window.setInterval(() => {
this._scrollToNext();
}, this._interval);
@@ -91,6 +99,11 @@ export class AIChatComposerTip extends LitElement {
private _scrollToNext() {
if (this.tips.length <= 1 || !this._tipListElement) return;
if (!this.loop && this._currentIndex >= this.tips.length - 1) {
this._stopAutoScroll();
return;
}
const list = this._tipListElement;
const firstItem = list.firstElementChild as HTMLElement;
@@ -100,11 +113,23 @@ export class AIChatComposerTip extends LitElement {
list.style.transition = 'margin-top ' + this._animDuration + 'ms';
list.style.marginTop = '-' + TIP_HEIGHT + 'px';
// After the animation ends: reorder the list and reset the position
setTimeout(function () {
list.style.transition = 'none'; // Immediately disable transition to reset position instantly without animation
list.append(firstItem); // Move the original first item to the bottom to achieve cyclic order
list.style.marginTop = '0'; // Reset the list position to the initial state
setTimeout(() => {
list.style.transition = 'none';
if (this.loop) {
list.append(firstItem);
list.style.marginTop = '0';
this._currentIndex++;
} else {
// Non-looping: only scroll if not at the last tip
if (this._currentIndex < this.tips.length - 1) {
list.append(firstItem);
list.style.marginTop = '0';
this._currentIndex++;
} else {
// When reaching the last tip, keep the position unchanged
list.style.marginTop = '0';
}
}
}, this._animDuration);
}

View File

@@ -153,6 +153,7 @@ export class AIChatComposer extends SignalWatcher(
html`<span>AI outputs can be misleading or wrong</span>`,
html`<ai-chat-embedding-status-tooltip .host=${this.host} />`,
]}
.loop=${false}
></ai-chat-composer-tip>
</div>
</div>`;

View File

@@ -9,9 +9,14 @@ import { AIProvider } from '../../provider/ai-provider';
export class AIChatEmbeddingStatusTooltip extends SignalWatcher(LitElement) {
static override styles = css`
:host {
width: 100%;
}
.embedding-status {
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
gap: 4px;
user-select: none;
}
@@ -80,17 +85,19 @@ export class AIChatEmbeddingStatusTooltip extends SignalWatcher(LitElement) {
class="embedding-status"
data-testid="ai-chat-embedding-status-tooltip"
>
<span class="embedding-status-text">
<div class="embedding-status-text">
Better results after embedding finished.
</span>
<span
</div>
<div
class="check-status"
data-testid="ai-chat-embedding-status-tooltip-check"
@mouseenter=${this._handleCheckStatusMouseEnter}
>
Check status
</span>
<affine-tooltip>${this.progressText}</affine-tooltip>
<affine-tooltip tip-position="top-start"
>${this.progressText}</affine-tooltip
>
</div>
</div>
`;
}