JimmFly
2024-05-28 06:19:59 +00:00
parent 2ca77d9170
commit 9d296c4b62
2 changed files with 106 additions and 54 deletions

View File

@@ -1,12 +1,7 @@
import { cssVar } from '@toeverything/theme'; import { cssVar } from '@toeverything/theme';
import { createVar, style } from '@vanilla-extract/css'; import { style } from '@vanilla-extract/css';
export const panelWidthVar = createVar('panel-width');
export const container = style({ export const container = style({
vars: {
[panelWidthVar]: '0px',
},
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
@@ -14,7 +9,9 @@ export const container = style({
position: 'fixed', position: 'fixed',
right: '28px', right: '28px',
top: '80px', top: '80px',
transform: `translateX(calc(${panelWidthVar} * -1))`, borderRadius: '8px',
boxShadow: cssVar('shadow3'),
border: `0.5px solid ${cssVar('borderColor')}`,
}); });
export const leftContent = style({ export const leftContent = style({
@@ -23,15 +20,35 @@ export const leftContent = style({
flex: 1, flex: 1,
}); });
export const searchIcon = style({
fontSize: '20px',
color: cssVar('iconColor'),
verticalAlign: 'middle',
});
export const inputContainer = style({ export const inputContainer = style({
display: 'flex', display: 'flex',
alignSelf: 'stretch',
alignItems: 'center', alignItems: 'center',
gap: '8px', gap: '8px',
flex: 1, flex: 1,
height: '32px', height: '32px',
position: 'relative', position: 'relative',
margin: '0 8px', padding: '0 8px',
borderRadius: '4px',
background: cssVar('white10'),
border: `1px solid ${cssVar('borderColor')}`,
selectors: {
'&.active': {
borderColor: cssVar('primaryColor'),
},
},
});
export const inputMain = style({
display: 'flex',
alignItems: 'center',
flex: 1,
height: '32px',
position: 'relative',
}); });
export const input = style({ export const input = style({
@@ -41,14 +58,13 @@ export const input = style({
height: '100%', height: '100%',
width: '100%', width: '100%',
color: 'transparent', color: 'transparent',
background: cssVar('white10'),
}); });
export const inputHack = style([ export const inputHack = style([
input, input,
{ {
'::placeholder': { '::placeholder': {
color: cssVar('iconColor'), color: cssVar('textPrimaryColor'),
}, },
pointerEvents: 'none', pointerEvents: 'none',
}, },
@@ -68,9 +84,13 @@ export const arrowButton = style({
flexShrink: 0, flexShrink: 0,
border: '1px solid', border: '1px solid',
borderColor: cssVar('borderColor'), borderColor: cssVar('borderColor'),
color: cssVar('iconSecondary'),
alignItems: 'baseline', alignItems: 'baseline',
background: 'transparent', background: 'transparent',
selectors: { selectors: {
'&:hover': {
color: cssVar('iconColor'),
},
'&.backward': { '&.backward': {
marginLeft: '8px', marginLeft: '8px',
borderRadius: '4px 0 0 4px', borderRadius: '4px 0 0 4px',
@@ -81,3 +101,12 @@ export const arrowButton = style({
}, },
}, },
}); });
export const closeButton = style({
padding: '4px',
fontSize: '20px',
width: '24px',
height: '24px',
flexShrink: 0,
color: cssVar('iconColor'),
marginLeft: '8px',
});

View File

@@ -1,10 +1,12 @@
import { Button, Modal } from '@affine/component'; import { Button, IconButton, Modal } from '@affine/component';
import { rightSidebarWidthAtom } from '@affine/core/atoms'; import {
import { ArrowDownSmallIcon, ArrowUpSmallIcon } from '@blocksuite/icons'; ArrowDownSmallIcon,
ArrowUpSmallIcon,
CloseIcon,
SearchIcon,
} from '@blocksuite/icons';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx'; import clsx from 'clsx';
import { useAtomValue } from 'jotai';
import { import {
type KeyboardEventHandler, type KeyboardEventHandler,
useCallback, useCallback,
@@ -13,7 +15,6 @@ import {
useState, useState,
} from 'react'; } from 'react';
import { RightSidebarService } from '../../right-sidebar';
import { FindInPageService } from '../services/find-in-page'; import { FindInPageService } from '../services/find-in-page';
import * as styles from './find-in-page-modal.css'; import * as styles from './find-in-page-modal.css';
@@ -26,12 +27,20 @@ const drawText = (canvas: HTMLCanvasElement, text: string) => {
const dpr = window.devicePixelRatio || 1; const dpr = window.devicePixelRatio || 1;
canvas.width = canvas.getBoundingClientRect().width * dpr; canvas.width = canvas.getBoundingClientRect().width * dpr;
canvas.height = canvas.getBoundingClientRect().height * dpr; canvas.height = canvas.getBoundingClientRect().height * dpr;
const rootStyles = getComputedStyle(document.documentElement);
const textColor = rootStyles
.getPropertyValue('--affine-text-primary-color')
.trim();
ctx.scale(dpr, dpr); ctx.scale(dpr, dpr);
ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = textColor;
ctx.font = '15px Inter'; ctx.font = '15px Inter';
ctx.fillText(text, 0, 22); ctx.fillText(text, 0, 22);
ctx.textAlign = 'left'; ctx.textAlign = 'left';
ctx.textBaseline = 'ideographic'; ctx.textBaseline = 'middle';
}; };
const CanvasText = ({ const CanvasText = ({
@@ -69,11 +78,8 @@ export const FindInPageModal = () => {
const result = useLiveData(findInPage.result$); const result = useLiveData(findInPage.result$);
const isSearching = useLiveData(findInPage.isSearching$); const isSearching = useLiveData(findInPage.isSearching$);
const rightSidebarWidth = useAtomValue(rightSidebarWidthAtom);
const rightSidebar = useService(RightSidebarService).rightSidebar;
const frontView = useLiveData(rightSidebar.front$);
const open = useLiveData(rightSidebar.isOpen$) && frontView !== undefined;
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const [active, setActive] = useState(false);
const handleValueChange = useCallback( const handleValueChange = useCallback(
(v: string) => { (v: string) => {
@@ -87,6 +93,14 @@ export const FindInPageModal = () => {
[findInPage] [findInPage]
); );
const handleFocus = useCallback(() => {
setActive(true);
}, []);
const handleBlur = useCallback(() => {
setActive(false);
}, []);
useEffect(() => { useEffect(() => {
if (visible) { if (visible) {
setValue(findInPage.searchText$.value || ''); setValue(findInPage.searchText$.value || '');
@@ -148,9 +162,6 @@ export const FindInPageModal = () => {
}, },
[handleBackWard, handleForward] [handleBackWard, handleForward]
); );
const panelWidth = assignInlineVars({
[styles.panelWidthVar]: open ? `${rightSidebarWidth}px` : '0',
});
return ( return (
<Modal <Modal
@@ -162,35 +173,43 @@ export const FindInPageModal = () => {
minHeight={48} minHeight={48}
contentOptions={{ contentOptions={{
className: styles.container, className: styles.container,
style: panelWidth,
}} }}
> >
<div className={styles.leftContent}> <div className={styles.leftContent}>
<div className={styles.inputContainer}> <div
<input className={clsx(styles.inputContainer, {
type="text" active: active,
autoFocus })}
value={value} >
ref={inputRef} <SearchIcon className={styles.searchIcon} />
style={{ <div className={styles.inputMain}>
visibility: isSearching ? 'hidden' : 'visible', <input
}} type="text"
className={styles.input} autoFocus
onKeyDown={handleKeydown} value={value}
onChange={e => handleValueChange(e.target.value)} ref={inputRef}
/> style={{
<CanvasText className={styles.inputHack} text={value} /> visibility: isSearching ? 'hidden' : 'visible',
</div> }}
<div className={styles.count}> onBlur={handleBlur}
{value.length > 0 && result && result.matches !== 0 ? ( onFocus={handleFocus}
<> className={styles.input}
<span>{result?.activeMatchOrdinal || 0}</span> onKeyDown={handleKeydown}
<span>/</span> onChange={e => handleValueChange(e.target.value)}
<span>{result?.matches || 0}</span> />
</> <CanvasText className={styles.inputHack} text={value} />
) : value.length ? ( </div>
<span>No matches</span> <div className={styles.count}>
) : null} {value.length > 0 && result && result.matches !== 0 ? (
<>
<span>{result?.activeMatchOrdinal || 0}</span>
<span>/</span>
<span>{result?.matches || 0}</span>
</>
) : value.length ? (
<span>No matches</span>
) : null}
</div>
</div> </div>
<Button <Button
@@ -206,9 +225,13 @@ export const FindInPageModal = () => {
<ArrowDownSmallIcon /> <ArrowDownSmallIcon />
</Button> </Button>
</div> </div>
<Button type="primary" onClick={handleDone}> <IconButton
Done className={styles.closeButton}
</Button> type="plain"
onClick={handleDone}
>
<CloseIcon />
</IconButton>
</Modal> </Modal>
); );
}; };