mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-29 08:09:52 +08:00
@@ -78,7 +78,7 @@ const MobileTextValue = ({
|
|||||||
}: PropertyValueProps) => {
|
}: PropertyValueProps) => {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
const [tempValue, setTempValue] = useState<string>(value);
|
const [tempValue, setTempValue] = useState<string>(value || '');
|
||||||
const handleClick = useCallback((e: React.MouseEvent) => {
|
const handleClick = useCallback((e: React.MouseEvent) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
@@ -111,20 +111,21 @@ const MobileTextValue = ({
|
|||||||
}, [onChange, tempValue]);
|
}, [onChange, tempValue]);
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTempValue(value);
|
setTempValue(value || '');
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PropertyValue
|
<>
|
||||||
className={styles.textPropertyValueContainer}
|
<PropertyValue
|
||||||
onClick={handleClick}
|
className={styles.textPropertyValueContainer}
|
||||||
isEmpty={!value}
|
onClick={handleClick}
|
||||||
>
|
isEmpty={!value}
|
||||||
<div className={styles.mobileTextareaPlain} data-empty={!tempValue}>
|
>
|
||||||
{tempValue ||
|
<div className={styles.mobileTextareaPlain} data-empty={!tempValue}>
|
||||||
t['com.affine.page-properties.property-value-placeholder']()}
|
{tempValue ||
|
||||||
</div>
|
t['com.affine.page-properties.property-value-placeholder']()}
|
||||||
|
</div>
|
||||||
|
</PropertyValue>
|
||||||
<ConfigModal
|
<ConfigModal
|
||||||
open={open}
|
open={open}
|
||||||
onOpenChange={setOpen}
|
onOpenChange={setOpen}
|
||||||
@@ -154,7 +155,7 @@ const MobileTextValue = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ConfigModal>
|
</ConfigModal>
|
||||||
</PropertyValue>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -44,9 +44,6 @@ export const ConfigModal = ({
|
|||||||
animation="slideBottom"
|
animation="slideBottom"
|
||||||
withoutCloseButton
|
withoutCloseButton
|
||||||
contentOptions={{
|
contentOptions={{
|
||||||
onClick: e => {
|
|
||||||
e.stopPropagation();
|
|
||||||
},
|
|
||||||
className:
|
className:
|
||||||
variant === 'page'
|
variant === 'page'
|
||||||
? styles.pageModalContent
|
? styles.pageModalContent
|
||||||
|
|||||||
@@ -64,7 +64,11 @@ export const SettingDropdownSelect = <
|
|||||||
))}
|
))}
|
||||||
{...menuOptions}
|
{...menuOptions}
|
||||||
>
|
>
|
||||||
<div className={clsx(styles.root, className)} {...attrs}>
|
<div
|
||||||
|
data-testid="dropdown-select-trigger"
|
||||||
|
className={clsx(styles.root, className)}
|
||||||
|
{...attrs}
|
||||||
|
>
|
||||||
<span className={styles.label}>{selectedItem?.label ?? ''}</span>
|
<span className={styles.label}>{selectedItem?.label ?? ''}</span>
|
||||||
|
|
||||||
<ArrowDownSmallIcon className={styles.icon} />
|
<ArrowDownSmallIcon className={styles.icon} />
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ export const RowLayout = ({
|
|||||||
href,
|
href,
|
||||||
}: PropsWithChildren<{ label: ReactNode; href?: string }>) => {
|
}: PropsWithChildren<{ label: ReactNode; href?: string }>) => {
|
||||||
const content = (
|
const content = (
|
||||||
<ConfigModal.Row className={styles.baseSettingItem}>
|
<ConfigModal.Row
|
||||||
|
data-testid="setting-row"
|
||||||
|
className={styles.baseSettingItem}
|
||||||
|
>
|
||||||
<div className={styles.baseSettingItemName}>{label}</div>
|
<div className={styles.baseSettingItemName}>{label}</div>
|
||||||
<div className={styles.baseSettingItemAction}>
|
<div className={styles.baseSettingItemAction}>
|
||||||
{children ||
|
{children ||
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ export const HomeHeader = () => {
|
|||||||
onClick={openSetting}
|
onClick={openSetting}
|
||||||
size={28}
|
size={28}
|
||||||
icon={<SettingsIcon />}
|
icon={<SettingsIcon />}
|
||||||
|
data-testid="settings-button"
|
||||||
/>
|
/>
|
||||||
</SafeArea>
|
</SafeArea>
|
||||||
</>
|
</>
|
||||||
|
|||||||
+3
-2
@@ -97,7 +97,8 @@ const MobileRichTextCell = ({
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const name = useLiveData(cell.property.name$);
|
const name = useLiveData(cell.property.name$);
|
||||||
return (
|
return (
|
||||||
<PropertyValue onClick={() => setOpen(true)}>
|
<>
|
||||||
|
<PropertyValue onClick={() => setOpen(true)}></PropertyValue>
|
||||||
<ConfigModal
|
<ConfigModal
|
||||||
onBack={() => setOpen(false)}
|
onBack={() => setOpen(false)}
|
||||||
open={open}
|
open={open}
|
||||||
@@ -125,7 +126,7 @@ const MobileRichTextCell = ({
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
rowId={rowId}
|
rowId={rowId}
|
||||||
/>
|
/>
|
||||||
</PropertyValue>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { test } from '@affine-test/kit/mobile';
|
||||||
|
import { expect, type Page } from '@playwright/test';
|
||||||
|
|
||||||
|
const openSettings = async (page: Page) => {
|
||||||
|
await page.getByTestId('settings-button').click();
|
||||||
|
await expect(page.getByRole('dialog')).toBeVisible();
|
||||||
|
await expect(page.locator('header:has-text("Settings")')).toBeVisible();
|
||||||
|
};
|
||||||
|
|
||||||
|
test('can open settings', async ({ page }) => {
|
||||||
|
await openSettings(page);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('can change theme', async ({ page }) => {
|
||||||
|
await openSettings(page);
|
||||||
|
await page
|
||||||
|
.getByTestId('setting-row')
|
||||||
|
.filter({
|
||||||
|
hasText: 'Color mode',
|
||||||
|
})
|
||||||
|
.getByTestId('dropdown-select-trigger')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
page.getByRole('dialog').filter({
|
||||||
|
has: page.getByRole('menuitem', { name: 'Light' }),
|
||||||
|
})
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByRole('menuitem', { name: 'Dark' }).click();
|
||||||
|
|
||||||
|
await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('can close change theme popover by clicking outside', async ({ page }) => {
|
||||||
|
await openSettings(page);
|
||||||
|
await page
|
||||||
|
.getByTestId('setting-row')
|
||||||
|
.filter({
|
||||||
|
hasText: 'Color mode',
|
||||||
|
})
|
||||||
|
.getByTestId('dropdown-select-trigger')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
const themePopover = page.getByRole('dialog').filter({
|
||||||
|
has: page.getByRole('menuitem', { name: 'Light' }),
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(themePopover).toBeVisible();
|
||||||
|
|
||||||
|
// get a mouse position that is 10px offset to the top of theme popover
|
||||||
|
// and click
|
||||||
|
const mousePosition = await themePopover.boundingBox();
|
||||||
|
if (!mousePosition) {
|
||||||
|
throw new Error('theme popover is not visible');
|
||||||
|
}
|
||||||
|
await page.mouse.click(mousePosition.x, mousePosition.y - 10);
|
||||||
|
|
||||||
|
await expect(themePopover).not.toBeVisible();
|
||||||
|
});
|
||||||
@@ -10,19 +10,21 @@ const config: PlaywrightTestConfig = {
|
|||||||
timeout: process.env.CI ? 60_000 : 30_000,
|
timeout: process.env.CI ? 60_000 : 30_000,
|
||||||
outputDir: testResultDir,
|
outputDir: testResultDir,
|
||||||
projects: [
|
projects: [
|
||||||
{
|
process.env.CI
|
||||||
name: 'Mobile Safari',
|
? {
|
||||||
use: {
|
name: 'Mobile Safari',
|
||||||
...devices['iPhone 14'],
|
use: {
|
||||||
},
|
...devices['iPhone 14'],
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
{
|
{
|
||||||
name: 'Mobile Chrome',
|
name: 'Mobile Chrome',
|
||||||
use: {
|
use: {
|
||||||
...devices['Pixel 5'],
|
...devices['Pixel 5'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
].filter(config => config !== undefined),
|
||||||
expect: {
|
expect: {
|
||||||
timeout: process.env.CI ? 15_000 : 5_000,
|
timeout: process.env.CI ? 15_000 : 5_000,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user