mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-18 14:56:59 +08:00
feat(core): open external link in web search result (#13362)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Search results now include clickable links that open in a new tab when available, improving navigation from AI-generated results. * **Style** * Enhanced visual feedback for linked search results, including updated cursor and hover effects for better user experience. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Wu Yue <akumatus@gmail.com>
This commit is contained in:
@@ -6,11 +6,13 @@ import { ToggleDownIcon, ToolIcon } from '@blocksuite/icons/lit';
|
|||||||
import { type Signal } from '@preact/signals-core';
|
import { type Signal } from '@preact/signals-core';
|
||||||
import { css, html, nothing, type TemplateResult } from 'lit';
|
import { css, html, nothing, type TemplateResult } from 'lit';
|
||||||
import { property, state } from 'lit/decorators.js';
|
import { property, state } from 'lit/decorators.js';
|
||||||
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||||
|
|
||||||
export interface ToolResult {
|
export interface ToolResult {
|
||||||
title: string | TemplateResult<1>;
|
title: string | TemplateResult<1>;
|
||||||
icon?: string | TemplateResult<1>;
|
icon?: string | TemplateResult<1>;
|
||||||
content?: string;
|
content?: string;
|
||||||
|
href?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ToolResultCard extends SignalWatcher(
|
export class ToolResultCard extends SignalWatcher(
|
||||||
@@ -18,6 +20,7 @@ export class ToolResultCard extends SignalWatcher(
|
|||||||
) {
|
) {
|
||||||
static override styles = css`
|
static override styles = css`
|
||||||
.ai-tool-result-wrapper {
|
.ai-tool-result-wrapper {
|
||||||
|
display: block;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
margin: 8px 0;
|
margin: 8px 0;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -88,6 +91,12 @@ export class ToolResultCard extends SignalWatcher(
|
|||||||
|
|
||||||
.result-item {
|
.result-item {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
|
display: block;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-item[href] {
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-item:first-child {
|
.result-item:first-child {
|
||||||
@@ -144,6 +153,37 @@ export class ToolResultCard extends SignalWatcher(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result-item[href]:hover .result-title,
|
||||||
|
.result-item[href]:hover .result-content {
|
||||||
|
color: ${unsafeCSSVarV2('text/primary')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-icon,
|
||||||
|
.footer-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 100%;
|
||||||
|
background-color: ${unsafeCSSVarV2('layer/background/primary')};
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 100%;
|
||||||
|
border: 0.5px solid ${unsafeCSSVarV2('layer/insideBorder/border')};
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
color: ${unsafeCSSVarV2('icon/primary')};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-item[href]:hover .result-title,
|
||||||
|
.result-item[href]:hover .result-content {
|
||||||
|
color: ${unsafeCSSVarV2('text/primary')};
|
||||||
|
}
|
||||||
|
|
||||||
.footer-icons {
|
.footer-icons {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -202,7 +242,14 @@ export class ToolResultCard extends SignalWatcher(
|
|||||||
<div class="ai-tool-results-content">
|
<div class="ai-tool-results-content">
|
||||||
${this.results.map(
|
${this.results.map(
|
||||||
result => html`
|
result => html`
|
||||||
<div class="result-item">
|
<a
|
||||||
|
class="result-item"
|
||||||
|
href=${ifDefined(result.href)}
|
||||||
|
target=${ifDefined(result.href ? '_blank' : undefined)}
|
||||||
|
rel=${ifDefined(
|
||||||
|
result.href ? 'noopener noreferrer' : undefined
|
||||||
|
)}
|
||||||
|
>
|
||||||
<div class="result-header">
|
<div class="result-header">
|
||||||
<div class="result-title">${result.title}</div>
|
<div class="result-title">${result.title}</div>
|
||||||
<div class="result-icon">
|
<div class="result-icon">
|
||||||
@@ -214,7 +261,7 @@ export class ToolResultCard extends SignalWatcher(
|
|||||||
${result.content}
|
${result.content}
|
||||||
</div>`
|
</div>`
|
||||||
: nothing}
|
: nothing}
|
||||||
</div>
|
</a>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -56,11 +56,12 @@ export class WebSearchTool extends WithDisposable(ShadowlessElement) {
|
|||||||
const result = this.data.result;
|
const result = this.data.result;
|
||||||
if (result && Array.isArray(result)) {
|
if (result && Array.isArray(result)) {
|
||||||
const results = result.map(item => {
|
const results = result.map(item => {
|
||||||
const { favicon, title, content } = item;
|
const { favicon, title, content, url } = item;
|
||||||
return {
|
return {
|
||||||
title: title,
|
title: title,
|
||||||
icon: favicon || WebIcon(),
|
icon: favicon || WebIcon(),
|
||||||
content: content,
|
content: content,
|
||||||
|
href: url,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
const footerIcons = result.map(item => item.favicon).filter(Boolean);
|
const footerIcons = result.map(item => item.favicon).filter(Boolean);
|
||||||
|
|||||||
Reference in New Issue
Block a user