feat: v5 general improvements (#2948)
* feat(v5): General fixes and improvements * add changeset * fix: bundlesize
This commit is contained in:
parent
8c01259d81
commit
5eac1fd6bb
14 changed files with 152 additions and 93 deletions
30
.changeset/better-cars-smell.md
Normal file
30
.changeset/better-cars-smell.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
"@docsearch/docusaurus-adapter": patch
|
||||
"@docsearch/react": patch
|
||||
"@docsearch/css": patch
|
||||
---
|
||||
|
||||
feat(v5): General UI styling updates and fixes
|
||||
|
||||
- New `--docsearch-font-family` variable, used by the search button, keyboard
|
||||
keys, modal, and sidepanel. It replaces the system font stacks that were
|
||||
duplicated across `sidepanel.css` and `button.css`, so overriding one
|
||||
variable now themes every DocSearch surface
|
||||
- The search input and modal heading are `1rem` at every breakpoint
|
||||
(previously `0.875rem` with a mobile-only override)
|
||||
- `.DocSearch-Title` uses `line-height: 1.5em` instead of `0.5em` and adds
|
||||
`overflow-wrap: anywhere`, so long titles wrap instead of overlapping (#2908)
|
||||
- Hit icon `svg` sizing moved into `.DocSearch-Hit-icon`. The
|
||||
`.DocSearch-Hit-icon--small` modifier is replaced by
|
||||
`.DocSearch-Hit-icon--start`, which top-aligns the icon; recent
|
||||
conversations use it
|
||||
- The Ask AI button icon centers with `display: inline-flex` instead of
|
||||
`margin-block-start`/`align-self` overrides
|
||||
- Removed the 2px offset on the Ask AI sources action text
|
||||
- `SourcesPanel` accepts `pluralTitleText`. `titleText` is now the singular
|
||||
label, and the trigger renders `{count} {label}`
|
||||
- `AskAiScreenTranslations` and `ConversationScreenTranslations` expose
|
||||
`relatedSourcesTextPlural`
|
||||
- Docusaurus adapter: `theme.SearchModal.askAiScreen.relatedSourcesText` is
|
||||
now the singular "Source", and the new
|
||||
`theme.SearchModal.askAiScreen.relatedSourcesTextPlural` provides "Sources"
|
||||
|
|
@ -39,6 +39,7 @@ const translations: DocSearchTranslations & {
|
|||
askAiScreen: {
|
||||
disclaimerText: string;
|
||||
relatedSourcesText: string;
|
||||
relatedSourcesTextPlural: string;
|
||||
thinkingText: string;
|
||||
copyButtonText: string;
|
||||
copyButtonCopiedText: string;
|
||||
|
|
@ -237,8 +238,13 @@ const translations: DocSearchTranslations & {
|
|||
}),
|
||||
relatedSourcesText: translate({
|
||||
id: 'theme.SearchModal.askAiScreen.relatedSourcesText',
|
||||
message: 'Related sources',
|
||||
description: 'The text for related sources',
|
||||
message: 'Source',
|
||||
description: 'Text shown describing a singular related source',
|
||||
}),
|
||||
relatedSourcesTextPlural: translate({
|
||||
id: 'theme.SearchModal.askAiScreen.relatedSourcesTextPlural',
|
||||
message: 'Sources',
|
||||
description: 'Text shown describing multiple related sources',
|
||||
}),
|
||||
thinkingText: translate({
|
||||
id: 'theme.SearchModal.askAiScreen.thinkingText',
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"files": [
|
||||
{
|
||||
"path": "packages/docsearch-css/dist/style.css",
|
||||
"maxSize": "8 kB"
|
||||
"maxSize": "8.05 kB"
|
||||
},
|
||||
{
|
||||
"path": "packages/docsearch-react/dist/umd/index.js",
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { test, expect } from './fixtures';
|
||||
import { test, expect, gatherA11yViolations } from './fixtures';
|
||||
|
||||
test.describe('a11y', () => {
|
||||
test.describe('a11y > Modal', () => {
|
||||
test.beforeEach(async ({ docSearch }) => {
|
||||
await docSearch.goto();
|
||||
await docSearch.waitForLoad();
|
||||
});
|
||||
|
||||
test.fail('Smoke test > Modal', async ({ docSearch, axe }, testInfo) => {
|
||||
test('Smoke test', async ({ docSearch, axe }, testInfo) => {
|
||||
await docSearch.openModal();
|
||||
|
||||
const scanResults = await axe().include('.DocSearch-Container').analyze();
|
||||
|
|
@ -16,10 +16,42 @@ test.describe('a11y', () => {
|
|||
contentType: 'application/json',
|
||||
});
|
||||
|
||||
expect(scanResults.violations).toEqual([]);
|
||||
// 6 is the current number of reported violations
|
||||
expect(
|
||||
gatherA11yViolations(scanResults.violations).length
|
||||
).toBeLessThanOrEqual(6);
|
||||
});
|
||||
|
||||
test.fail('Smoke test > Sidepanel', async ({ sidepanel, axe }, testInfo) => {
|
||||
test('Search results', async ({ docSearch, axe }, testInfo) => {
|
||||
await docSearch.openModal();
|
||||
|
||||
await docSearch.typeQueryMatching();
|
||||
|
||||
await expect(docSearch.hits).toBeVisible();
|
||||
|
||||
const scanResults = await axe()
|
||||
.include('#docsearch-hits_docsearch-list')
|
||||
.analyze();
|
||||
|
||||
await testInfo.attach('a11y-scan-results-modal-search-results', {
|
||||
body: JSON.stringify(scanResults.violations, null, 2),
|
||||
contentType: 'application/json',
|
||||
});
|
||||
|
||||
// 24 is the current number of reported violations
|
||||
expect(
|
||||
gatherA11yViolations(scanResults.violations).length
|
||||
).toBeLessThanOrEqual(24);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('a11y > Sidepanel', () => {
|
||||
test.beforeEach(async ({ docSearch, sidepanel }) => {
|
||||
await docSearch.goto();
|
||||
await sidepanel.waitForLoad();
|
||||
});
|
||||
|
||||
test('Smoke test', async ({ sidepanel, axe }, testInfo) => {
|
||||
await sidepanel.openSidepanel();
|
||||
|
||||
const scanResults = await axe()
|
||||
|
|
@ -31,6 +63,9 @@ test.describe('a11y', () => {
|
|||
contentType: 'application/json',
|
||||
});
|
||||
|
||||
expect(scanResults.violations).toEqual([]);
|
||||
// 4 is the current number of reported violations
|
||||
expect(
|
||||
gatherA11yViolations(scanResults.violations).length
|
||||
).toBeLessThanOrEqual(4);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -102,6 +102,10 @@ export class SidepanelPage {
|
|||
this.sidepanel = page.locator('.DocSearch-Sidepanel-Container');
|
||||
}
|
||||
|
||||
async waitForLoad(): Promise<void> {
|
||||
await expect(this.sidepanelButton).toBeVisible({ timeout: 10000 });
|
||||
}
|
||||
|
||||
async openSidepanel(): Promise<void> {
|
||||
await this.sidepanelButton.click();
|
||||
await expect(this.sidepanel).toHaveClass(/is-open/, {
|
||||
|
|
@ -137,4 +141,10 @@ export const test = base.extend<{
|
|||
},
|
||||
});
|
||||
|
||||
export { expect };
|
||||
type AxeScanResults = Awaited<ReturnType<AxeBuilder['analyze']>>;
|
||||
|
||||
function gatherA11yViolations(violations: AxeScanResults['violations']) {
|
||||
return violations.flatMap((v) => v.nodes);
|
||||
}
|
||||
|
||||
export { expect, gatherA11yViolations };
|
||||
|
|
|
|||
|
|
@ -84,14 +84,13 @@
|
|||
/* Ask AI Button */
|
||||
|
||||
.DocSearch-Hit-AskAIButton {
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.DocSearch-Hit-AskAIButton-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-inline-end: 8px;
|
||||
margin-block-start: 0;
|
||||
align-self: unset;
|
||||
}
|
||||
|
||||
.DocSearch-Hit-AskAIButton-title {
|
||||
|
|
@ -1011,20 +1010,23 @@
|
|||
gap: 1ch;
|
||||
border-radius: 100vw;
|
||||
border: 1px solid var(--docsearch-subtle-color);
|
||||
background: transparent;
|
||||
background-color: transparent;
|
||||
padding-inline: 0.75em;
|
||||
padding-block: 0.375em;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
color: var(--docsearch-text-color);
|
||||
transition: all 0.2s ease;
|
||||
transition:
|
||||
background-color 0.2s ease,
|
||||
border-color 0.2s ease,
|
||||
color 0.2s ease;
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--docsearch-soft-primary-color);
|
||||
background-color: var(--docsearch-soft-primary-color);
|
||||
color: var(--docsearch-highlight-color);
|
||||
border-color: var(--docsearch-soft-primary-color);
|
||||
}
|
||||
|
|
@ -1047,7 +1049,6 @@
|
|||
}
|
||||
|
||||
.DocSearch-AskAiScreen-Sources-Action-text {
|
||||
margin-block-start: 2px;
|
||||
font-size: 1em;
|
||||
line-height: 1.15em;
|
||||
white-space: nowrap;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
/* Variables */
|
||||
|
||||
:root {
|
||||
/* stylelint-disable-next-line value-keyword-case */
|
||||
--docsearch-font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
--docsearch-primary-color: rgb(0 61 255);
|
||||
--docsearch-primary-dark-color: rgb(2 46 185 / 100%);
|
||||
--docsearch-soft-primary-color: rgb(0 61 255 / 10%);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
justify-content: space-between;
|
||||
padding: 0 8px;
|
||||
user-select: none;
|
||||
font-family: var(--docsearch-font-family);
|
||||
}
|
||||
|
||||
.DocSearch-Button-Container {
|
||||
|
|
@ -58,10 +59,7 @@
|
|||
justify-content: center;
|
||||
position: relative;
|
||||
font-size: 14px;
|
||||
font-family:
|
||||
system-ui,
|
||||
-apple-system,
|
||||
sans-serif;
|
||||
font-family: var(--docsearch-font-family);
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 100ms;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
margin: 60px auto auto;
|
||||
max-width: var(--docsearch-modal-width);
|
||||
position: relative;
|
||||
font-family: var(--docsearch-font-family);
|
||||
}
|
||||
|
||||
.DocSearch-Popover-Positioner {
|
||||
|
|
@ -442,7 +443,7 @@
|
|||
color: var(--docsearch-text-color);
|
||||
flex: 1;
|
||||
font: inherit;
|
||||
font-size: 0.875rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
height: 100%;
|
||||
outline: none;
|
||||
|
|
@ -656,8 +657,9 @@
|
|||
color: var(--docsearch-text-color);
|
||||
vertical-align: middle;
|
||||
font-size: 1.1em;
|
||||
line-height: 0.5em;
|
||||
line-height: 1.5em;
|
||||
font-weight: 300;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.DocSearch-Title strong {
|
||||
|
|
@ -777,23 +779,16 @@
|
|||
height: 24px;
|
||||
stroke-width: var(--docsearch-icon-stroke-width);
|
||||
width: 24px;
|
||||
|
||||
svg {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.DocSearch-Hit-icon--start {
|
||||
align-self: flex-start;
|
||||
margin-block-start: 0.8em;
|
||||
}
|
||||
|
||||
.DocSearch-Hit-icon svg {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.DocSearch-Hit-icon--small {
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
.DocSearch-Hit-icon--small svg {
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
margin-block-start: 0.5em;
|
||||
}
|
||||
|
||||
.DocSearch-Hit-action,
|
||||
|
|
@ -1114,10 +1109,6 @@ assistive tech users */
|
|||
--docsearch-footer-height: 48px;
|
||||
}
|
||||
|
||||
.DocSearch-Input {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Prevent body scroll on modal-open for mobile */
|
||||
|
||||
/* https://stackoverflow.com/a/24727206/6276948 */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
user-select: none;
|
||||
border: 0;
|
||||
transition: all 150ms ease-in-out;
|
||||
font-family: var(--docsearch-font-family);
|
||||
}
|
||||
|
||||
.DocSearch-SidepanelButton.floating {
|
||||
|
|
@ -90,18 +91,7 @@
|
|||
all: unset;
|
||||
cursor: pointer;
|
||||
transition: all 150ms ease-in-out;
|
||||
font-family:
|
||||
system-ui,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
'Open Sans',
|
||||
'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-family: var(--docsearch-font-family);
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +112,6 @@
|
|||
.DocSearch-Sidepanel-Container {
|
||||
position: fixed;
|
||||
min-width: 0;
|
||||
will-change: transform, width, opacity;
|
||||
overflow: hidden;
|
||||
box-shadow:
|
||||
0 0 0 1px rgb(35 38 59 / 5%),
|
||||
|
|
@ -132,12 +121,6 @@
|
|||
width: 100svw;
|
||||
}
|
||||
|
||||
@media screen and (prefers-reduced-motion: reduce) {
|
||||
.DocSearch-Sidepanel-Container {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
.DocSearch-Sidepanel-Container.inline,
|
||||
.DocSearch-Sidepanel-Container.floating {
|
||||
top: 0;
|
||||
|
|
@ -166,7 +149,10 @@
|
|||
@media screen and (width >= 769px) {
|
||||
.DocSearch-Sidepanel-Container {
|
||||
width: var(--sp-width);
|
||||
transition: all 280ms cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition:
|
||||
transform 280ms cubic-bezier(0.22, 1, 0.36, 1),
|
||||
opacity 280ms cubic-bezier(0.22, 1, 0.36, 1),
|
||||
width 280ms cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
.DocSearch-Sidepanel-Container.floating {
|
||||
|
|
@ -209,6 +195,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
@media screen and (prefers-reduced-motion: reduce) {
|
||||
.DocSearch-Sidepanel-Container {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
.DocSearch-Sidepanel-Container.is-open {
|
||||
opacity: 1;
|
||||
}
|
||||
|
|
@ -233,18 +225,7 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--docsearch-sidepanel-background);
|
||||
font-family:
|
||||
system-ui,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
'Open Sans',
|
||||
'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-family: var(--docsearch-font-family);
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
|
|
@ -442,18 +423,7 @@
|
|||
min-height: 1.5rem;
|
||||
height: 1.5rem;
|
||||
overflow: hidden;
|
||||
font-family:
|
||||
system-ui,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
'Open Sans',
|
||||
'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-family: var(--docsearch-font-family);
|
||||
}
|
||||
|
||||
.DocSearch-Sidepanel-Prompt--textarea::placeholder {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,10 @@ export type AskAiScreenTranslations = Partial<
|
|||
Omit<ToolCallTranslations, 'searchingText' | 'toolCallResultText'> & {
|
||||
// Misc texts
|
||||
disclaimerText: string;
|
||||
/** Text shown describing a singular related source. */
|
||||
relatedSourcesText: string;
|
||||
/** Text shown describing multiple related sources. */
|
||||
relatedSourcesTextPlural: string;
|
||||
thinkingText: string;
|
||||
copyButtonText: string;
|
||||
copyButtonCopiedText: string;
|
||||
|
|
@ -187,6 +190,7 @@ function AskAiExchangeCard({
|
|||
stoppedStreamingText = 'You stopped this response',
|
||||
errorTitleText = 'Chat error',
|
||||
relatedSourcesText,
|
||||
relatedSourcesTextPlural,
|
||||
suggestedPromptsTitleText = 'Suggested prompts',
|
||||
} = translations;
|
||||
|
||||
|
|
@ -355,7 +359,11 @@ function AskAiExchangeCard({
|
|||
)}
|
||||
</div>
|
||||
<div className="DocSearch-AskAiScreen-Answer-Footer">
|
||||
<SourcesPanel links={urlsToDisplay} titleText={relatedSourcesText} />
|
||||
<SourcesPanel
|
||||
links={urlsToDisplay}
|
||||
titleText={relatedSourcesText}
|
||||
pluralTitleText={relatedSourcesTextPlural}
|
||||
/>
|
||||
<FeedbackActions
|
||||
id={messageId}
|
||||
showActions={showActions}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,10 @@ export type ConversationScreenTranslations = Partial<
|
|||
reasoningText: string;
|
||||
/** Text show while assistant is thinking. */
|
||||
thinkingText: string;
|
||||
/** Text shown describing related sources. */
|
||||
/** Text shown describing a singular related source. */
|
||||
relatedSourcesText: string;
|
||||
/** Text shown describing multiple related sources. */
|
||||
relatedSourcesTextPlural: string;
|
||||
/** Message that's shown when user has stopped the streaming of a message. */
|
||||
stoppedStreamingText: string;
|
||||
/** Text shown for copy button on code snippets. */
|
||||
|
|
@ -119,6 +121,7 @@ const ConversationExchange = React.forwardRef<
|
|||
thinkingText = 'Thinking...',
|
||||
searchingText = 'Searching...',
|
||||
relatedSourcesText,
|
||||
relatedSourcesTextPlural,
|
||||
stoppedStreamingText = 'You stopped this response',
|
||||
preToolCallText = 'Searching...',
|
||||
toolCallResultText = 'Searched for',
|
||||
|
|
@ -281,6 +284,7 @@ const ConversationExchange = React.forwardRef<
|
|||
<SourcesPanel
|
||||
links={urlsToDisplay}
|
||||
titleText={relatedSourcesText}
|
||||
pluralTitleText={relatedSourcesTextPlural}
|
||||
/>
|
||||
<FeedbackActions
|
||||
isSidepanel={true}
|
||||
|
|
|
|||
|
|
@ -8,16 +8,20 @@ import { Popover } from './ui/Popover';
|
|||
interface SourcesProps {
|
||||
links: ExtractedLink[];
|
||||
titleText?: string;
|
||||
pluralTitleText?: string;
|
||||
}
|
||||
|
||||
export function SourcesPanel({
|
||||
links,
|
||||
titleText = 'Sources',
|
||||
titleText = 'Source',
|
||||
pluralTitleText = 'Sources',
|
||||
}: SourcesProps): JSX.Element | null {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const triggerRef = React.useRef<HTMLButtonElement>(null);
|
||||
const [boundary, setBoundary] = React.useState<HTMLElement | null>(null);
|
||||
|
||||
const sourcesTitle = links.length > 1 ? pluralTitleText : titleText;
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
return undefined;
|
||||
|
|
@ -73,7 +77,7 @@ export function SourcesPanel({
|
|||
<ContentIcon />
|
||||
</span>
|
||||
<span className="DocSearch-AskAiScreen-Sources-Action-text">
|
||||
{links.length} sources
|
||||
{links.length} {sourcesTitle}
|
||||
</span>
|
||||
</Popover.Trigger>
|
||||
<Popover.Popup
|
||||
|
|
@ -83,7 +87,7 @@ export function SourcesPanel({
|
|||
alignOffset={-16}
|
||||
collisionBoundary={boundary ?? 'clipping-ancestors'}
|
||||
>
|
||||
<Popover.Title>{titleText}</Popover.Title>
|
||||
<Popover.Title>{sourcesTitle}</Popover.Title>
|
||||
<ul className="DocSearch-AskAiScreen-Sources">
|
||||
{links.map((l) => (
|
||||
<li key={l.url} className="DocSearch-AskAiScreen-Sources-source">
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export function RecentConversationsResults({
|
|||
title={recentConversationsTitle}
|
||||
collection={recentConversations}
|
||||
renderIcon={() => (
|
||||
<div className="DocSearch-Hit-icon DocSearch-Hit-icon--small">
|
||||
<div className="DocSearch-Hit-icon DocSearch-Hit-icon--start">
|
||||
<MessageIcon />
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Reference in a new issue