mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-04 00:28:33 +00:00
fix(storybook): remove storybook testing (#6595)
remove tests/storybook @affine/components storybook still exists
This commit is contained in:
@@ -54,7 +54,6 @@ const allPackages = [
|
||||
'packages/common/theme',
|
||||
'packages/common/y-indexeddb',
|
||||
'tools/cli',
|
||||
'tests/storybook',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
51
.github/workflows/publish-storybook.yml
vendored
51
.github/workflows/publish-storybook.yml
vendored
@@ -1,51 +0,0 @@
|
||||
name: Publish Storybook
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- canary
|
||||
pull_request:
|
||||
branches:
|
||||
- canary
|
||||
paths-ignore:
|
||||
- README.md
|
||||
- .github/**
|
||||
- packages/backend/server
|
||||
- packages/frontend/electron
|
||||
- '!.github/workflows/publish-storybook.yml'
|
||||
|
||||
jobs:
|
||||
publish-storybook:
|
||||
name: Publish Storybook
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.merge_commit_sha }}
|
||||
# This is required to fetch all commits for chromatic
|
||||
fetch-depth: 0
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
with:
|
||||
electron-install: false
|
||||
- uses: chromaui/action-next@v1
|
||||
with:
|
||||
workingDir: tests/storybook
|
||||
buildScriptName: build
|
||||
exitOnceUploaded: true
|
||||
onlyChanged: false
|
||||
diagnostics: true
|
||||
env:
|
||||
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
NODE_OPTIONS: ${{ env.NODE_OPTIONS }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: chromatic-build-artifacts-${{ github.run_id }}
|
||||
path: |
|
||||
chromatic-diagnostics.json
|
||||
**/build-storybook.log
|
||||
51
.github/workflows/publish-ui-storybook.yml
vendored
51
.github/workflows/publish-ui-storybook.yml
vendored
@@ -1,51 +0,0 @@
|
||||
name: Publish UI Storybook
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- canary
|
||||
pull_request:
|
||||
branches:
|
||||
- canary
|
||||
paths-ignore:
|
||||
- README.md
|
||||
- .github/**
|
||||
- packages/backend/server
|
||||
- packages/frontend/electron
|
||||
- '!.github/workflows/publish-storybook.yml'
|
||||
|
||||
jobs:
|
||||
publish-ui-storybook:
|
||||
name: Publish UI Storybook
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.merge_commit_sha }}
|
||||
# This is required to fetch all commits for chromatic
|
||||
fetch-depth: 0
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
with:
|
||||
electron-install: false
|
||||
- uses: chromaui/action-next@v1
|
||||
with:
|
||||
workingDir: packages/frontend/component
|
||||
buildScriptName: build:storybook
|
||||
exitOnceUploaded: true
|
||||
onlyChanged: false
|
||||
diagnostics: true
|
||||
env:
|
||||
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_UI_PROJECT_TOKEN }}
|
||||
NODE_OPTIONS: ${{ env.NODE_OPTIONS }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: chromatic-build-artifacts-${{ github.run_id }}
|
||||
path: |
|
||||
chromatic-diagnostics.json
|
||||
**/build-storybook.log
|
||||
@@ -112,7 +112,7 @@ If you have questions, you are welcome to contact us. One of the best places to
|
||||
|
||||
| Name | | |
|
||||
| -------------------------------------------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [@affine/component](packages/frontend/component) | AFFiNE Component Resources | [](https://affine-storybook.vercel.app/) |
|
||||
| [@affine/component](packages/frontend/component) | AFFiNE Component Resources |  |
|
||||
| [@toeverything/y-indexeddb](packages/common/y-indexeddb) | IndexedDB database adapter for Yjs | [](https://www.npmjs.com/package/@toeverything/y-indexeddb) |
|
||||
| [@toeverything/theme](packages/common/theme) | AFFiNE theme | [](https://www.npmjs.com/package/@toeverything/theme) |
|
||||
|
||||
|
||||
@@ -54,12 +54,6 @@ yarn dev
|
||||
|
||||
See [building desktop client app](../building-desktop-client-app.md).
|
||||
|
||||
### `@affine/storybook`
|
||||
|
||||
```shell
|
||||
yarn workspace @affine/storybook storybook
|
||||
```
|
||||
|
||||
## What's next?
|
||||
|
||||
- [Behind the code](./behind-the-code.md)
|
||||
|
||||
@@ -22,9 +22,7 @@
|
||||
"build": "yarn nx build @affine/web",
|
||||
"build:electron": "yarn nx build @affine/electron",
|
||||
"build:storage": "yarn nx run-many -t build -p @affine/storage",
|
||||
"build:storybook": "yarn nx build @affine/storybook",
|
||||
"start:web-static": "yarn workspace @affine/web static-server",
|
||||
"start:storybook": "yarn exec serve tests/storybook/storybook-static -l 6006",
|
||||
"serve:test-static": "yarn exec serve tests/fixtures --cors -p 8081",
|
||||
"lint:eslint": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" eslint . --ext .js,mjs,.ts,.tsx --cache",
|
||||
"lint:eslint:fix": "yarn lint:eslint --fix",
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
import { runCli } from '@magic-works/i18n-codegen';
|
||||
import type { StorybookConfig } from '@storybook/react-vite';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { mergeConfig, type InlineConfig } from 'vite';
|
||||
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
|
||||
import { getRuntimeConfig } from '@affine/cli/src/webpack/runtime-config';
|
||||
|
||||
runCli(
|
||||
{
|
||||
config: fileURLToPath(
|
||||
new URL('../../../.i18n-codegen.json', import.meta.url)
|
||||
),
|
||||
watch: false,
|
||||
},
|
||||
error => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
);
|
||||
|
||||
export default {
|
||||
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
|
||||
staticDirs: ['../../../packages/frontend/core/public'],
|
||||
addons: [
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-interactions',
|
||||
'storybook-dark-mode',
|
||||
'storybook-addon-react-router-v6',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/react-vite',
|
||||
},
|
||||
async viteFinal(config, _options) {
|
||||
const runtimeConfig = getRuntimeConfig({
|
||||
distribution: 'browser',
|
||||
mode: 'development',
|
||||
channel: 'canary',
|
||||
coverage: false,
|
||||
});
|
||||
// disable for storybook build
|
||||
runtimeConfig.enableCloud = false;
|
||||
return mergeConfig<InlineConfig, InlineConfig>(config, {
|
||||
assetsInclude: ['**/*.md', '**/*.zip'],
|
||||
resolve: {
|
||||
alias: {
|
||||
// workaround for https://github.com/vitejs/vite/issues/9731
|
||||
// it seems vite does not resolve self reference correctly?
|
||||
'@affine/core': fileURLToPath(
|
||||
new URL('../../../packages/frontend/core/src', import.meta.url)
|
||||
),
|
||||
},
|
||||
},
|
||||
esbuild: {
|
||||
target: 'ES2022',
|
||||
},
|
||||
plugins: [vanillaExtractPlugin()],
|
||||
define: {
|
||||
'process.on': 'undefined',
|
||||
'process.env': {},
|
||||
'process.env.COVERAGE': JSON.stringify(!!process.env.COVERAGE),
|
||||
'process.env.SHOULD_REPORT_TRACE': `${Boolean(
|
||||
process.env.SHOULD_REPORT_TRACE === 'true'
|
||||
)}`,
|
||||
'process.env.TRACE_REPORT_ENDPOINT': `"${process.env.TRACE_REPORT_ENDPOINT}"`,
|
||||
'process.env.CAPTCHA_SITE_KEY': `"${process.env.CAPTCHA_SITE_KEY}"`,
|
||||
runtimeConfig: runtimeConfig,
|
||||
},
|
||||
});
|
||||
},
|
||||
} as StorybookConfig;
|
||||
@@ -1,2 +0,0 @@
|
||||
import 'core-js/modules/esnext.symbol.async-dispose';
|
||||
import 'core-js/modules/esnext.symbol.dispose';
|
||||
@@ -1,3 +0,0 @@
|
||||
<script>
|
||||
window.global = window;
|
||||
</script>
|
||||
@@ -1,193 +0,0 @@
|
||||
import './polyfill';
|
||||
import '@affine/component/theme/global.css';
|
||||
import '@affine/component/theme/theme.css';
|
||||
import '@affine/core/bootstrap/preload';
|
||||
import { createI18n } from '@affine/i18n';
|
||||
import { ThemeProvider, useTheme } from 'next-themes';
|
||||
import { useDarkMode } from 'storybook-dark-mode';
|
||||
import { AffineContext } from '@affine/component/context';
|
||||
import useSWR from 'swr';
|
||||
import type { Decorator } from '@storybook/react';
|
||||
import {
|
||||
FrameworkRoot,
|
||||
FrameworkScope,
|
||||
GlobalContextService,
|
||||
LifecycleService,
|
||||
WorkspacesService,
|
||||
_setCurrentStore,
|
||||
configureTestingInfraModules,
|
||||
useLiveData,
|
||||
} from '@toeverything/infra';
|
||||
import { setupGlobal, type Environment } from '@affine/env/global';
|
||||
|
||||
import type { Preview } from '@storybook/react';
|
||||
import { useLayoutEffect, useMemo, useRef } from 'react';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { Framework } from '@toeverything/infra';
|
||||
import { configureCommonModules } from '@affine/core/modules';
|
||||
import { createStore } from 'jotai';
|
||||
|
||||
setupGlobal();
|
||||
export const parameters = {
|
||||
backgrounds: { disable: true },
|
||||
actions: { argTypesRegex: '^on[A-Z].*' },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const i18n = createI18n();
|
||||
const withI18n: Decorator = (Story, context) => {
|
||||
const locale = context.globals.locale;
|
||||
useSWR(
|
||||
locale,
|
||||
async () => {
|
||||
await i18n.changeLanguage(locale);
|
||||
},
|
||||
{
|
||||
suspense: true,
|
||||
}
|
||||
);
|
||||
return <Story {...context} />;
|
||||
};
|
||||
|
||||
const ThemeChange = () => {
|
||||
const isDark = useDarkMode();
|
||||
const theme = useTheme();
|
||||
if (theme.resolvedTheme === 'dark' && !isDark) {
|
||||
theme.setTheme('light');
|
||||
} else if (theme.resolvedTheme === 'light' && isDark) {
|
||||
theme.setTheme('dark');
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
localStorage.clear();
|
||||
|
||||
// do not show onboarding for storybook
|
||||
window.localStorage.setItem('app_config', '{"onBoarding":false}');
|
||||
window.localStorage.setItem('dismissAiOnboarding', 'true');
|
||||
window.localStorage.setItem('dismissAiOnboardingEdgeless', 'true');
|
||||
window.localStorage.setItem('dismissAiOnboardingLocal', 'true');
|
||||
|
||||
const framework = new Framework();
|
||||
|
||||
configureCommonModules(framework);
|
||||
configureTestingInfraModules(framework);
|
||||
|
||||
const frameworkProvider = framework.provider();
|
||||
|
||||
frameworkProvider.get(LifecycleService).applicationStart();
|
||||
const globalContextService = frameworkProvider.get(GlobalContextService);
|
||||
|
||||
const store = createStore();
|
||||
_setCurrentStore(store);
|
||||
|
||||
frameworkProvider
|
||||
.get(WorkspacesService)
|
||||
.create(WorkspaceFlavour.LOCAL, async w => {
|
||||
w.meta.setName('test-workspace');
|
||||
w.meta.writeVersion(w);
|
||||
})
|
||||
.then(meta => {
|
||||
globalContextService.globalContext.workspaceId.set(meta.id);
|
||||
});
|
||||
|
||||
const withContextDecorator: Decorator = (Story, context) => {
|
||||
const workspaceId = useLiveData(
|
||||
globalContextService.globalContext.workspaceId.$
|
||||
);
|
||||
|
||||
const { workspace } =
|
||||
useMemo(() => {
|
||||
if (!workspaceId) {
|
||||
return null;
|
||||
}
|
||||
return frameworkProvider.get(WorkspacesService).open({
|
||||
metadata: { flavour: WorkspaceFlavour.LOCAL, id: workspaceId },
|
||||
});
|
||||
}, []) ?? {};
|
||||
|
||||
if (!workspace) {
|
||||
return <>loading..</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<FrameworkRoot framework={frameworkProvider}>
|
||||
<FrameworkScope scope={workspace.scope}>
|
||||
<ThemeProvider>
|
||||
<AffineContext store={store}>
|
||||
<ThemeChange />
|
||||
<Story {...context} />
|
||||
</AffineContext>
|
||||
</ThemeProvider>
|
||||
</FrameworkScope>
|
||||
</FrameworkRoot>
|
||||
);
|
||||
};
|
||||
|
||||
const platforms = ['web', 'desktop-macos', 'desktop-windows'] as const;
|
||||
|
||||
const withPlatformSelectionDecorator: Decorator = (Story, context) => {
|
||||
const setupCounterRef = useRef(0);
|
||||
useLayoutEffect(() => {
|
||||
if (setupCounterRef.current++ === 0) {
|
||||
return;
|
||||
}
|
||||
switch (context.globals.platform) {
|
||||
case 'desktop-macos':
|
||||
environment = {
|
||||
...environment,
|
||||
isBrowser: true,
|
||||
isDesktop: true,
|
||||
isMacOs: true,
|
||||
isWindows: false,
|
||||
} as Environment;
|
||||
break;
|
||||
case 'desktop-windows':
|
||||
environment = {
|
||||
...environment,
|
||||
isBrowser: true,
|
||||
isDesktop: true,
|
||||
isMacOs: false,
|
||||
isWindows: true,
|
||||
} as Environment;
|
||||
break;
|
||||
default:
|
||||
globalThis.$AFFINE_SETUP = false;
|
||||
setupGlobal();
|
||||
break;
|
||||
}
|
||||
}, [context.globals.platform]);
|
||||
|
||||
return <Story key={context.globals.platform} {...context} />;
|
||||
};
|
||||
|
||||
const decorators = [
|
||||
withContextDecorator,
|
||||
withI18n,
|
||||
withPlatformSelectionDecorator,
|
||||
];
|
||||
|
||||
const preview: Preview = {
|
||||
decorators,
|
||||
globalTypes: {
|
||||
platform: {
|
||||
description: 'Rendering platform target',
|
||||
defaultValue: 'web',
|
||||
toolbar: {
|
||||
// The label to show for this toolbar item
|
||||
title: 'platform',
|
||||
// Array of plain string values or MenuItem shape (see below)
|
||||
items: platforms,
|
||||
// Change title based on selected value
|
||||
dynamicTitle: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
||||
@@ -1 +0,0 @@
|
||||
# Storybook
|
||||
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"name": "@affine/storybook",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "storybook dev -p 6006",
|
||||
"build": "storybook build",
|
||||
"test": "test-storybook"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/cli": "workspace:*",
|
||||
"@affine/component": "workspace:*",
|
||||
"@affine/i18n": "workspace:*",
|
||||
"@dnd-kit/sortable": "^8.0.0",
|
||||
"@storybook/jest": "^0.2.3",
|
||||
"@storybook/testing-library": "^0.2.2",
|
||||
"foxact": "^0.2.33",
|
||||
"jotai": "^2.8.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nanoid": "^5.0.7",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"ses": "^1.4.1",
|
||||
"storybook-addon-react-router-v6": "^2.0.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blocksuite/block-std": "0.14.0-canary-202404151235-655ec84",
|
||||
"@blocksuite/blocks": "0.14.0-canary-202404151235-655ec84",
|
||||
"@blocksuite/global": "0.14.0-canary-202404151235-655ec84",
|
||||
"@blocksuite/icons": "2.1.46",
|
||||
"@blocksuite/inline": "0.14.0-canary-202404151235-655ec84",
|
||||
"@blocksuite/presets": "0.14.0-canary-202404151235-655ec84",
|
||||
"@blocksuite/store": "0.14.0-canary-202404151235-655ec84",
|
||||
"@storybook/addon-actions": "^7.6.17",
|
||||
"@storybook/addon-essentials": "^7.6.17",
|
||||
"@storybook/addon-interactions": "^7.6.17",
|
||||
"@storybook/addon-links": "^7.6.17",
|
||||
"@storybook/addon-storysource": "^7.6.17",
|
||||
"@storybook/blocks": "^7.6.17",
|
||||
"@storybook/builder-vite": "^7.6.17",
|
||||
"@storybook/react": "^7.6.17",
|
||||
"@storybook/react-vite": "^7.6.17",
|
||||
"@storybook/test-runner": "^0.17.0",
|
||||
"@vanilla-extract/esbuild-plugin": "^2.3.5",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"chromatic": "^11.3.0",
|
||||
"concurrently": "^8.2.2",
|
||||
"jest-mock": "^29.7.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"serve": "^14.2.1",
|
||||
"storybook": "^7.6.17",
|
||||
"storybook-dark-mode": "^3.0.3",
|
||||
"storybook-mock-date-decorator": "^1.0.2",
|
||||
"wait-on": "^7.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@blocksuite/blocks": "*",
|
||||
"@blocksuite/global": "*",
|
||||
"@blocksuite/icons": "2.1.34",
|
||||
"@blocksuite/presets": "*",
|
||||
"@blocksuite/store": "*"
|
||||
},
|
||||
"version": "0.14.0"
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
{
|
||||
"name": "@affine/storybook",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "nx:run-script",
|
||||
"dependsOn": ["^build"],
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
"{projectRoot}/.storybook/**/*",
|
||||
"{workspaceRoot}/packages/frontend/components/src/**/*",
|
||||
"{workspaceRoot}/packages/frontend/core/src/**/*",
|
||||
"{workspaceRoot}/packages/common/infra/**/*",
|
||||
{
|
||||
"runtime": "node -v"
|
||||
},
|
||||
{
|
||||
"env": "BUILD_TYPE"
|
||||
},
|
||||
{
|
||||
"env": "PERFSEE_TOKEN"
|
||||
},
|
||||
{
|
||||
"env": "SENTRY_ORG"
|
||||
},
|
||||
{
|
||||
"env": "SENTRY_PROJECT"
|
||||
},
|
||||
{
|
||||
"env": "SENTRY_AUTH_TOKEN"
|
||||
},
|
||||
{
|
||||
"env": "SENTRY_DSN"
|
||||
},
|
||||
{
|
||||
"env": "DISTRIBUTION"
|
||||
},
|
||||
{
|
||||
"env": "COVERAGE"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"script": "build"
|
||||
},
|
||||
"outputs": ["{projectRoot}/storybook-static"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import { BrowserWarning, LocalDemoTips } from '@affine/component/affine-banner';
|
||||
import type { StoryFn } from '@storybook/react';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/Banner',
|
||||
component: BrowserWarning,
|
||||
};
|
||||
|
||||
export const Default: StoryFn = () => {
|
||||
const [closed, setIsClosed] = useState(true);
|
||||
return (
|
||||
<div>
|
||||
<BrowserWarning
|
||||
message={<span>test</span>}
|
||||
show={closed}
|
||||
onClose={() => {
|
||||
setIsClosed(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Download: StoryFn = () => {
|
||||
const [, setIsClosed] = useState(true);
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||
return (
|
||||
<div>
|
||||
<LocalDemoTips
|
||||
isLoggedIn={isLoggedIn}
|
||||
onLogin={() => setIsLoggedIn(true)}
|
||||
onEnableCloud={() => {}}
|
||||
onClose={() => {
|
||||
setIsClosed(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,146 +0,0 @@
|
||||
import {
|
||||
AddPageButton,
|
||||
AppSidebar,
|
||||
AppSidebarFallback,
|
||||
appSidebarOpenAtom,
|
||||
CategoryDivider,
|
||||
MenuLinkItem,
|
||||
navHeaderStyle,
|
||||
QuickSearchInput,
|
||||
SidebarContainer,
|
||||
SidebarScrollableContainer,
|
||||
SidebarSwitch,
|
||||
} from '@affine/core/components/app-sidebar';
|
||||
import { DeleteTemporarilyIcon, SettingsIcon } from '@blocksuite/icons';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { useAtom } from 'jotai';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/AppSidebar',
|
||||
component: AppSidebar,
|
||||
} satisfies Meta;
|
||||
|
||||
const Container = ({ children }: PropsWithChildren) => (
|
||||
<MemoryRouter>
|
||||
<main
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: '100vw',
|
||||
height: 'calc(100vh - 40px)',
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</main>
|
||||
</MemoryRouter>
|
||||
);
|
||||
const Main = () => {
|
||||
const [open] = useAtom(appSidebarOpenAtom);
|
||||
return (
|
||||
<div>
|
||||
<div className={navHeaderStyle}>
|
||||
<SidebarSwitch show={!open} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Default: StoryFn = () => {
|
||||
return (
|
||||
<Container>
|
||||
<AppSidebar />
|
||||
<Main />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export const Fallback = () => {
|
||||
return (
|
||||
<Container>
|
||||
<AppSidebarFallback />
|
||||
<Main />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export const WithItems: StoryFn = () => {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
return (
|
||||
<Container>
|
||||
<AppSidebar>
|
||||
<SidebarContainer>
|
||||
<QuickSearchInput />
|
||||
<div style={{ height: '20px' }} />
|
||||
<MenuLinkItem
|
||||
icon={<SettingsIcon />}
|
||||
to="/test"
|
||||
onClick={() => alert('opened')}
|
||||
>
|
||||
Settings
|
||||
</MenuLinkItem>
|
||||
<MenuLinkItem
|
||||
icon={<SettingsIcon />}
|
||||
to="/test"
|
||||
onClick={() => alert('opened')}
|
||||
>
|
||||
Settings
|
||||
</MenuLinkItem>
|
||||
<MenuLinkItem
|
||||
icon={<SettingsIcon />}
|
||||
to="/test"
|
||||
onClick={() => alert('opened')}
|
||||
>
|
||||
Settings
|
||||
</MenuLinkItem>
|
||||
</SidebarContainer>
|
||||
|
||||
<SidebarScrollableContainer>
|
||||
<CategoryDivider label="Favorites" />
|
||||
<MenuLinkItem
|
||||
collapsed={collapsed}
|
||||
onCollapsedChange={setCollapsed}
|
||||
icon={<SettingsIcon />}
|
||||
to="/test"
|
||||
onClick={() => alert('opened')}
|
||||
>
|
||||
Collapsible Item
|
||||
</MenuLinkItem>
|
||||
<MenuLinkItem
|
||||
collapsed={!collapsed}
|
||||
onCollapsedChange={setCollapsed}
|
||||
icon={<SettingsIcon />}
|
||||
to="/test"
|
||||
onClick={() => alert('opened')}
|
||||
>
|
||||
Collapsible Item
|
||||
</MenuLinkItem>
|
||||
<MenuLinkItem
|
||||
icon={<SettingsIcon />}
|
||||
to="/test"
|
||||
onClick={() => alert('opened')}
|
||||
>
|
||||
Settings
|
||||
</MenuLinkItem>
|
||||
|
||||
<CategoryDivider label="Others" />
|
||||
<MenuLinkItem
|
||||
icon={<DeleteTemporarilyIcon />}
|
||||
to="/test"
|
||||
onClick={() => alert('opened')}
|
||||
>
|
||||
Trash
|
||||
</MenuLinkItem>
|
||||
</SidebarScrollableContainer>
|
||||
<SidebarContainer>
|
||||
<AddPageButton />
|
||||
</SidebarContainer>
|
||||
</AppSidebar>
|
||||
<Main />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
import type { AddPageButtonProps } from '@affine/core/components/app-sidebar';
|
||||
import { AppUpdaterButton } from '@affine/core/components/app-sidebar';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/AppUpdaterButton',
|
||||
component: AppUpdaterButton,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta<typeof AppUpdaterButton>;
|
||||
|
||||
const Container = ({ children }: PropsWithChildren) => (
|
||||
<main
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: '320px',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
backgroundColor: '#eee',
|
||||
padding: '16px',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</main>
|
||||
);
|
||||
|
||||
export const Default: StoryFn<AddPageButtonProps> = props => {
|
||||
return (
|
||||
<Container>
|
||||
<AppUpdaterButton {...props} />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
Default.args = {
|
||||
appQuitting: false,
|
||||
updateReady: true,
|
||||
updateAvailable: {
|
||||
version: '1.0.0-beta.1',
|
||||
allowAutoUpdate: true,
|
||||
},
|
||||
downloadProgress: 42,
|
||||
changelogUnread: true,
|
||||
autoDownload: false,
|
||||
};
|
||||
|
||||
export const Updated: StoryFn<AddPageButtonProps> = props => {
|
||||
return (
|
||||
<Container>
|
||||
<AppUpdaterButton {...props} updateAvailable={null} />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
Updated.args = {
|
||||
changelogUnread: true,
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
import { BlockSuiteEditor } from '@affine/core/components/blocksuite/block-suite-editor';
|
||||
import { AffineSchemas } from '@blocksuite/blocks/schemas';
|
||||
import { DocCollection, Schema } from '@blocksuite/store';
|
||||
import type { StoryFn } from '@storybook/react';
|
||||
import { initEmptyPage } from '@toeverything/infra';
|
||||
|
||||
const schema = new Schema();
|
||||
schema.register(AffineSchemas);
|
||||
|
||||
async function createAndInitPage(
|
||||
docCollection: DocCollection,
|
||||
title: string,
|
||||
preview: string
|
||||
) {
|
||||
const doc = docCollection.createDoc();
|
||||
initEmptyPage(doc, title);
|
||||
doc.getBlockByFlavour('affine:paragraph').at(0)?.text?.insert(preview, 0);
|
||||
return doc;
|
||||
}
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/BlocksuiteEditor/DocEditor',
|
||||
};
|
||||
|
||||
export const DocEditor: StoryFn<typeof BlockSuiteEditor> = (_, { loaded }) => {
|
||||
return (
|
||||
<div style={{ height: '100vh' }}>
|
||||
<BlockSuiteEditor mode="page" page={loaded.page} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
DocEditor.loaders = [
|
||||
async () => {
|
||||
const docCollection = new DocCollection({
|
||||
id: 'test-workspace-id',
|
||||
schema,
|
||||
});
|
||||
docCollection.doc.emit('sync', [true, docCollection.doc]);
|
||||
docCollection.meta.setProperties({
|
||||
tags: {
|
||||
options: [],
|
||||
},
|
||||
});
|
||||
|
||||
const page = await createAndInitPage(
|
||||
docCollection,
|
||||
'This is page 1',
|
||||
'Hello World from page 1'
|
||||
);
|
||||
|
||||
return {
|
||||
page,
|
||||
workspace: docCollection,
|
||||
};
|
||||
},
|
||||
];
|
||||
@@ -1,67 +0,0 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { BlockCard } from '@affine/component/card/block-card';
|
||||
import { WorkspaceCard } from '@affine/component/card/workspace-card';
|
||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import {
|
||||
EdgelessIcon,
|
||||
ExportToHtmlIcon,
|
||||
HelpIcon,
|
||||
PageIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import type { Meta } from '@storybook/react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/Card',
|
||||
component: WorkspaceCard,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
export const AffineWorkspaceCard = () => {
|
||||
return (
|
||||
<WorkspaceCard
|
||||
meta={{
|
||||
id: 'blocksuite-local',
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
}}
|
||||
onClick={() => {}}
|
||||
onSettingClick={() => {}}
|
||||
currentWorkspaceId={null}
|
||||
isOwner={true}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const AffineBlockCard = () => {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
|
||||
<BlockCard title={'New Page'} onClick={() => toast('clicked')} />
|
||||
<BlockCard
|
||||
title={'New Page'}
|
||||
desc={'Write with a blank page'}
|
||||
right={<PageIcon width={20} height={20} />}
|
||||
onClick={() => toast('clicked page')}
|
||||
/>
|
||||
<BlockCard
|
||||
title={'New Edgeless'}
|
||||
desc={'Draw with a blank whiteboard'}
|
||||
left={<PageIcon width={20} height={20} />}
|
||||
right={<EdgelessIcon width={20} height={20} />}
|
||||
onClick={() => toast('clicked edgeless')}
|
||||
/>
|
||||
<BlockCard
|
||||
left={<ExportToHtmlIcon width={20} height={20} />}
|
||||
title="HTML"
|
||||
disabled
|
||||
right={
|
||||
<Tooltip content={'Learn how to Import pages into AFFiNE.'}>
|
||||
<HelpIcon />
|
||||
</Tooltip>
|
||||
}
|
||||
onClick={() => toast('click HTML')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
import { Checkbox } from '@affine/component';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/Checkbox',
|
||||
component: Checkbox,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta<typeof Checkbox>;
|
||||
|
||||
export const Basic: StoryFn<typeof Checkbox> = props => {
|
||||
const [checked, setChecked] = useState(props.checked);
|
||||
const handleChange = (
|
||||
_event: React.ChangeEvent<HTMLInputElement>,
|
||||
checked: boolean
|
||||
) => {
|
||||
setChecked(checked);
|
||||
props.onChange?.(_event, checked);
|
||||
};
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '1rem',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Checkbox
|
||||
style={{ fontSize: 14 }}
|
||||
{...props}
|
||||
checked={checked}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Checkbox
|
||||
style={{ fontSize: 16 }}
|
||||
{...props}
|
||||
checked={checked}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Checkbox
|
||||
style={{ fontSize: 18 }}
|
||||
{...props}
|
||||
checked={checked}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Checkbox
|
||||
style={{ fontSize: 24 }}
|
||||
{...props}
|
||||
checked={checked}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Basic.args = {
|
||||
checked: true,
|
||||
disabled: false,
|
||||
indeterminate: false,
|
||||
onChange: console.log,
|
||||
};
|
||||
@@ -1,227 +0,0 @@
|
||||
import { NavigateContext, topLevelRoutes } from '@affine/core/router';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type { StoryFn } from '@storybook/react';
|
||||
import { screen, userEvent, waitFor, within } from '@storybook/testing-library';
|
||||
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
reactRouterOutlets,
|
||||
reactRouterParameters,
|
||||
withRouter,
|
||||
} from 'storybook-addon-react-router-v6';
|
||||
import { mockDateDecorator } from 'storybook-mock-date-decorator';
|
||||
|
||||
const FakeApp = () => {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
// fixme: `key` is a hack to force the storybook to re-render the outlet
|
||||
return (
|
||||
<NavigateContext.Provider value={navigate}>
|
||||
<Outlet key={location.pathname} />
|
||||
</NavigateContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
title: 'Preview/Core',
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: false },
|
||||
},
|
||||
};
|
||||
|
||||
export const Index: StoryFn = () => {
|
||||
return <FakeApp />;
|
||||
};
|
||||
Index.decorators = [withRouter];
|
||||
Index.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(
|
||||
topLevelRoutes[0].children /* skip root wrapper */
|
||||
),
|
||||
}),
|
||||
};
|
||||
|
||||
export const SettingPage: StoryFn = () => {
|
||||
return <FakeApp />;
|
||||
};
|
||||
SettingPage.play = async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await waitFor(
|
||||
async () => {
|
||||
assertExists(
|
||||
document.body.querySelector(
|
||||
'[data-testid="slider-bar-workspace-setting-button"]'
|
||||
)
|
||||
);
|
||||
},
|
||||
{
|
||||
timeout: 10000,
|
||||
}
|
||||
);
|
||||
await step('click setting modal button', async () => {
|
||||
await userEvent.click(
|
||||
canvas.getByTestId('slider-bar-workspace-setting-button')
|
||||
);
|
||||
});
|
||||
await waitFor(async () => {
|
||||
assertExists(
|
||||
document.body.querySelector('[data-testid="language-menu-button"]')
|
||||
);
|
||||
});
|
||||
|
||||
// Menu button may have "pointer-events: none" style, await 100ms to avoid this weird situation.
|
||||
await new Promise(resolve => window.setTimeout(resolve, 100));
|
||||
|
||||
await step('click language menu button', async () => {
|
||||
await userEvent.click(
|
||||
document.body.querySelector(
|
||||
'[data-testid="language-menu-button"]'
|
||||
) as HTMLElement
|
||||
);
|
||||
});
|
||||
};
|
||||
SettingPage.decorators = [withRouter];
|
||||
SettingPage.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(topLevelRoutes),
|
||||
}),
|
||||
};
|
||||
|
||||
export const NotFoundPage: StoryFn = () => {
|
||||
return <FakeApp />;
|
||||
};
|
||||
NotFoundPage.decorators = [withRouter];
|
||||
NotFoundPage.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(topLevelRoutes),
|
||||
location: {
|
||||
path: '/404',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export const WorkspaceList: StoryFn = () => {
|
||||
return <FakeApp />;
|
||||
};
|
||||
WorkspaceList.play = async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
// click current-workspace
|
||||
const currentWorkspace = await waitFor(
|
||||
() => {
|
||||
assertExists(canvas.getByTestId('current-workspace'));
|
||||
return canvas.getByTestId('current-workspace');
|
||||
},
|
||||
{
|
||||
timeout: 5000,
|
||||
}
|
||||
);
|
||||
|
||||
// todo: figure out why userEvent cannot click this element?
|
||||
// await userEvent.click(currentWorkspace);
|
||||
currentWorkspace.click();
|
||||
};
|
||||
WorkspaceList.decorators = [withRouter];
|
||||
WorkspaceList.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(topLevelRoutes),
|
||||
location: {
|
||||
path: '/',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export const SearchPage: StoryFn = () => {
|
||||
return <FakeApp />;
|
||||
};
|
||||
SearchPage.play = async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await waitFor(
|
||||
async () => {
|
||||
assertExists(
|
||||
document.body.querySelector(
|
||||
'[data-testid="slider-bar-quick-search-button"]'
|
||||
)
|
||||
);
|
||||
},
|
||||
{
|
||||
timeout: 3000,
|
||||
}
|
||||
);
|
||||
await userEvent.click(canvas.getByTestId('slider-bar-quick-search-button'));
|
||||
await waitFor(
|
||||
() => {
|
||||
assertExists(screen.getByTestId('cmdk-quick-search'));
|
||||
},
|
||||
{
|
||||
timeout: 3000,
|
||||
}
|
||||
);
|
||||
};
|
||||
SearchPage.decorators = [withRouter];
|
||||
SearchPage.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(topLevelRoutes),
|
||||
location: {
|
||||
path: '/',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export const ImportPage: StoryFn = () => {
|
||||
return <FakeApp />;
|
||||
};
|
||||
ImportPage.play = async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await waitFor(
|
||||
async () => {
|
||||
assertExists(
|
||||
document.body.querySelector('[data-testid="sidebar-new-page-button"]')
|
||||
);
|
||||
},
|
||||
{
|
||||
timeout: 10000,
|
||||
}
|
||||
);
|
||||
await userEvent.click(canvas.getByTestId('sidebar-new-page-button'));
|
||||
await waitFor(() => {
|
||||
assertExists(canvasElement.querySelector('v-line'));
|
||||
});
|
||||
await waitFor(() => {
|
||||
assertExists(
|
||||
canvasElement.querySelector('[data-testid="header-dropDownButton"]')
|
||||
);
|
||||
});
|
||||
await userEvent.click(canvas.getByTestId('header-dropDownButton'));
|
||||
await waitFor(() => {
|
||||
assertExists(
|
||||
document.body.querySelector('[data-testid="editor-option-menu-import"]')
|
||||
);
|
||||
});
|
||||
await userEvent.click(screen.getByTestId('editor-option-menu-import'));
|
||||
};
|
||||
ImportPage.decorators = [withRouter, mockDateDecorator];
|
||||
ImportPage.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(topLevelRoutes),
|
||||
location: {
|
||||
path: '/',
|
||||
},
|
||||
}),
|
||||
date: new Date('Mon, 25 Mar 2024 08:39:07 GMT'),
|
||||
};
|
||||
|
||||
export const OpenAppPage: StoryFn = () => {
|
||||
return <FakeApp />;
|
||||
};
|
||||
OpenAppPage.decorators = [withRouter];
|
||||
OpenAppPage.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(topLevelRoutes),
|
||||
location: {
|
||||
path: '/open-app/url',
|
||||
searchParams: {
|
||||
url: 'affine-beta://foo-bar.com',
|
||||
open: 'false',
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
@@ -1,96 +0,0 @@
|
||||
import { BlockSuiteEditor } from '@affine/core/components/blocksuite/block-suite-editor';
|
||||
import { ImagePreviewModal } from '@affine/core/components/image-preview';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import type { Doc } from '@toeverything/infra';
|
||||
import {
|
||||
DocsService,
|
||||
FrameworkScope,
|
||||
initEmptyPage,
|
||||
useService,
|
||||
WorkspaceService,
|
||||
} from '@toeverything/infra';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { mockDateDecorator } from 'storybook-mock-date-decorator';
|
||||
|
||||
export default {
|
||||
title: 'Component/ImagePreviewModal',
|
||||
component: ImagePreviewModal,
|
||||
} satisfies Meta;
|
||||
|
||||
export const Default: StoryFn = () => {
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const docsService = useService(DocsService);
|
||||
|
||||
const [doc, setDoc] = useState<Doc | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const bsDoc = workspace.docCollection.createDoc({ id: 'page0' });
|
||||
initEmptyPage(bsDoc);
|
||||
|
||||
const { doc, release } = docsService.open(bsDoc.meta!.id);
|
||||
|
||||
fetch(new URL('@affine-test/fixtures/large-image.png', import.meta.url))
|
||||
.then(res => res.arrayBuffer())
|
||||
.then(async buffer => {
|
||||
const id = await workspace.docCollection.blob.set(
|
||||
new Blob([buffer], { type: 'image/png' })
|
||||
);
|
||||
const frameId = bsDoc.getBlockByFlavour('affine:note')[0].id;
|
||||
bsDoc.addBlock(
|
||||
'affine:paragraph',
|
||||
{
|
||||
text: new bsDoc.Text(
|
||||
'Please double click the image to preview it.'
|
||||
),
|
||||
},
|
||||
frameId
|
||||
);
|
||||
bsDoc.addBlock(
|
||||
'affine:image',
|
||||
{
|
||||
sourceId: id,
|
||||
},
|
||||
frameId
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Failed to load large-image.png', err);
|
||||
});
|
||||
setDoc(doc);
|
||||
|
||||
return () => {
|
||||
release();
|
||||
};
|
||||
}, [docsService, workspace]);
|
||||
|
||||
if (!doc) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return (
|
||||
<FrameworkScope scope={doc.scope}>
|
||||
<div
|
||||
style={{
|
||||
height: '100vh',
|
||||
width: '100vw',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<BlockSuiteEditor mode="page" page={doc.blockSuiteDoc} />
|
||||
{createPortal(
|
||||
<ImagePreviewModal
|
||||
pageId={doc.id}
|
||||
docCollection={doc.blockSuiteDoc.collection}
|
||||
/>,
|
||||
document.body
|
||||
)}
|
||||
</div>
|
||||
</FrameworkScope>
|
||||
);
|
||||
};
|
||||
|
||||
Default.decorators = [mockDateDecorator];
|
||||
Default.parameters = {
|
||||
date: new Date('Mon, 25 Mar 2024 08:39:07 GMT'),
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
/* deepscan-disable USELESS_ARROW_FUNC_BIND */
|
||||
import { toast } from '@affine/component';
|
||||
import { ImportPage } from '@affine/component/import-page';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/ImportPage',
|
||||
component: ImportPage,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
const Template: StoryFn<typeof ImportPage> = args => <ImportPage {...args} />;
|
||||
|
||||
export const Basic = Template.bind(undefined);
|
||||
Basic.args = {
|
||||
importHtml: () => toast('Click importHtml'),
|
||||
importMarkdown: () => toast('Click importMarkdown'),
|
||||
importNotion: () => toast('Click importNotion'),
|
||||
onClose: () => toast('Click onClose'),
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
import { Input } from '@affine/component';
|
||||
import { expect } from '@storybook/jest';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/Input',
|
||||
component: Input,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta<typeof Input>;
|
||||
|
||||
export const Basic: StoryFn<typeof Input> = () => {
|
||||
return <Input data-testid="test-input" defaultValue="test" />;
|
||||
};
|
||||
|
||||
Basic.play = async ({ canvasElement }) => {
|
||||
const element = within(canvasElement);
|
||||
const item = element.getByTestId('test-input') as HTMLInputElement;
|
||||
expect(item).toBeTruthy();
|
||||
expect(item.value).toBe('test');
|
||||
await userEvent.clear(item);
|
||||
await userEvent.type(item, 'test 2');
|
||||
expect(item.value).toBe('test 2');
|
||||
};
|
||||
|
||||
export const DynamicHeight: StoryFn<typeof Input> = () => {
|
||||
return <Input style={{ width: '200px' }} data-testid="test-input" />;
|
||||
};
|
||||
|
||||
DynamicHeight.play = async ({ canvasElement }) => {
|
||||
const element = within(canvasElement);
|
||||
const item = element.getByTestId('test-input') as HTMLInputElement;
|
||||
expect(item).toBeTruthy();
|
||||
// FIXME: the following is not correct
|
||||
// expect(item.getBoundingClientRect().width).toBe(200);
|
||||
};
|
||||
|
||||
export const NoBorder: StoryFn<typeof Input> = () => {
|
||||
return <Input noBorder={true} data-testid="test-input" />;
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Meta } from '@storybook/blocks';
|
||||
|
||||
<Meta title="Introduction" />
|
||||
|
||||
# AFFiNE UI Storybook
|
||||
|
||||
This is a UI component dev environment for AFFiNE UI.
|
||||
It allows you to browse the AFFiNE UI components,
|
||||
view the different states of each component,
|
||||
and interactively develop and test components.
|
||||
|
||||
## Bug Reporting
|
||||
|
||||
If you find a bug, please file an issue on [GitHub](https://github.com/toeverything/AFFiNE/issues)
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions from the community! [Get started here](https://github.com/toeverything/AFFiNE/blob/canary/docs/BUILDING.md)
|
||||
@@ -1,249 +0,0 @@
|
||||
import {
|
||||
expandNotificationCenterAtom,
|
||||
NotificationCenter,
|
||||
pushNotificationAtom,
|
||||
} from '@affine/component/notification-center';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/NotificationCenter',
|
||||
component: NotificationCenter,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta<typeof NotificationCenter>;
|
||||
|
||||
let id = 0;
|
||||
const image = (
|
||||
<video autoPlay muted loop>
|
||||
<source
|
||||
src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
|
||||
type="video/mp4"
|
||||
/>
|
||||
</video>
|
||||
);
|
||||
export const Basic = () => {
|
||||
const push = useSetAtom(pushNotificationAtom);
|
||||
const expand = useAtomValue(expandNotificationCenterAtom);
|
||||
return (
|
||||
<>
|
||||
<div>{expand ? 'expanded' : 'collapsed'}</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: `${key} message`,
|
||||
timeout: 3000,
|
||||
progressingBar: true,
|
||||
action: async () => {
|
||||
console.log('undo');
|
||||
},
|
||||
type: 'info',
|
||||
});
|
||||
}}
|
||||
>
|
||||
Push timeout notification
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: `${key} message`,
|
||||
type: 'info',
|
||||
});
|
||||
}}
|
||||
>
|
||||
Push notification with no timeout
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: ``,
|
||||
type: 'info',
|
||||
});
|
||||
}}
|
||||
>
|
||||
Push notification with no message
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: ``,
|
||||
type: 'success',
|
||||
theme: 'light',
|
||||
});
|
||||
}}
|
||||
>
|
||||
light success
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: ``,
|
||||
type: 'success',
|
||||
theme: 'dark',
|
||||
});
|
||||
}}
|
||||
>
|
||||
dark success
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: ``,
|
||||
type: 'info',
|
||||
theme: 'light',
|
||||
});
|
||||
}}
|
||||
>
|
||||
light info
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: ``,
|
||||
type: 'info',
|
||||
theme: 'dark',
|
||||
});
|
||||
}}
|
||||
>
|
||||
dark info
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: ``,
|
||||
type: 'warning',
|
||||
theme: 'light',
|
||||
});
|
||||
}}
|
||||
>
|
||||
light warning
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: ``,
|
||||
type: 'warning',
|
||||
theme: 'dark',
|
||||
});
|
||||
}}
|
||||
>
|
||||
dark warning
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: ``,
|
||||
type: 'error',
|
||||
theme: 'light',
|
||||
});
|
||||
}}
|
||||
>
|
||||
light error
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: ``,
|
||||
type: 'error',
|
||||
theme: 'dark',
|
||||
});
|
||||
}}
|
||||
>
|
||||
dark error
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
key: `${key}`,
|
||||
title: `${key} title`,
|
||||
message: `gif test`,
|
||||
type: 'info',
|
||||
multimedia: image,
|
||||
timeout: 3000,
|
||||
action: async () => {
|
||||
console.log('undo');
|
||||
},
|
||||
progressingBar: true,
|
||||
});
|
||||
}}
|
||||
>
|
||||
gif
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const key = id++;
|
||||
push({
|
||||
title: `${key} title`,
|
||||
type: 'info',
|
||||
theme: 'default',
|
||||
timeout: 3000,
|
||||
});
|
||||
}}
|
||||
>
|
||||
default message
|
||||
</button>
|
||||
</div>
|
||||
<NotificationCenter />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
import type { Input } from '@affine/component';
|
||||
import { Onboarding } from '@affine/core/components/affine/onboarding/onboarding';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
|
||||
export default {
|
||||
title: 'Preview/Onboarding',
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta<typeof Input>;
|
||||
|
||||
export const Preview: StoryFn<typeof Onboarding> = () => {
|
||||
return <Onboarding />;
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
import { PageDetailSkeleton } from '@affine/component/page-detail-skeleton';
|
||||
import type { Meta } from '@storybook/react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/PageDetailSkeleton',
|
||||
component: PageDetailSkeleton,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta<typeof PageDetailSkeleton>;
|
||||
|
||||
export const Basic = () => {
|
||||
return <PageDetailSkeleton />;
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
import { PagePropertiesTable } from '@affine/core/components/affine/page-properties';
|
||||
import { AffineSchemas } from '@blocksuite/blocks/schemas';
|
||||
import { DocCollection, Schema } from '@blocksuite/store';
|
||||
import type { StoryFn } from '@storybook/react';
|
||||
import { initEmptyPage } from '@toeverything/infra';
|
||||
|
||||
const schema = new Schema();
|
||||
schema.register(AffineSchemas);
|
||||
|
||||
async function createAndInitPage(
|
||||
docCollection: DocCollection,
|
||||
title: string,
|
||||
preview: string
|
||||
) {
|
||||
const page = docCollection.createDoc();
|
||||
initEmptyPage(page, title);
|
||||
page.getBlockByFlavour('affine:paragraph').at(0)?.text?.insert(preview, 0);
|
||||
return page;
|
||||
}
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/PageInfoProperties',
|
||||
};
|
||||
|
||||
export const PageInfoProperties: StoryFn<typeof PagePropertiesTable> = (
|
||||
_,
|
||||
{ loaded }
|
||||
) => {
|
||||
return (
|
||||
<div style={{ height: '100vh' }}>
|
||||
<PagePropertiesTable page={loaded.page} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
PageInfoProperties.loaders = [
|
||||
async () => {
|
||||
const docCollection = new DocCollection({
|
||||
id: 'test-workspace-id',
|
||||
schema,
|
||||
});
|
||||
docCollection.doc.emit('sync', [true, docCollection.doc]);
|
||||
docCollection.meta.setProperties({
|
||||
tags: {
|
||||
options: [],
|
||||
},
|
||||
});
|
||||
|
||||
const page = await createAndInitPage(
|
||||
docCollection,
|
||||
'This is page 1',
|
||||
'Hello World from page 1'
|
||||
);
|
||||
|
||||
if (page.meta) {
|
||||
page.meta.updatedDate = Date.now();
|
||||
}
|
||||
|
||||
return {
|
||||
page,
|
||||
workspace: docCollection,
|
||||
};
|
||||
},
|
||||
];
|
||||
@@ -1,349 +0,0 @@
|
||||
import { toast } from '@affine/component';
|
||||
import type {
|
||||
ListItem,
|
||||
ListProps,
|
||||
PageListItemProps,
|
||||
PageOperationCellProps,
|
||||
PageTagsProps,
|
||||
} from '@affine/core/components/page-list';
|
||||
import {
|
||||
FloatingToolbar,
|
||||
List,
|
||||
ListScrollContainer,
|
||||
NewPageButton,
|
||||
PageListItem,
|
||||
PageOperationCell,
|
||||
PageTags,
|
||||
} from '@affine/core/components/page-list';
|
||||
import { topLevelRoutes } from '@affine/core/router';
|
||||
import { AffineSchemas } from '@blocksuite/blocks/schemas';
|
||||
import { PageIcon, TagsIcon } from '@blocksuite/icons';
|
||||
import { DocCollection, Schema } from '@blocksuite/store';
|
||||
import { expect } from '@storybook/jest';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { userEvent } from '@storybook/testing-library';
|
||||
import { initEmptyPage } from '@toeverything/infra';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
reactRouterOutlets,
|
||||
reactRouterParameters,
|
||||
withRouter,
|
||||
} from 'storybook-addon-react-router-v6';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/PageList',
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
export const AffineOperationCell: StoryFn<PageOperationCellProps> = ({
|
||||
...props
|
||||
}) => <PageOperationCell {...props} />;
|
||||
|
||||
AffineOperationCell.args = {
|
||||
page: {
|
||||
id: '123',
|
||||
title: 'Test Page Title',
|
||||
tags: ['tag1', 'tag2'],
|
||||
createDate: new Date('2021-01-01').getTime(),
|
||||
},
|
||||
};
|
||||
AffineOperationCell.parameters = {
|
||||
reactRouter: reactRouterParameters({
|
||||
routing: reactRouterOutlets(topLevelRoutes),
|
||||
}),
|
||||
};
|
||||
AffineOperationCell.play = async ({ canvasElement }) => {
|
||||
{
|
||||
const button = canvasElement.querySelector(
|
||||
'[data-testid="page-list-operation-button"]'
|
||||
) as HTMLButtonElement;
|
||||
expect(button).not.toBeNull();
|
||||
await userEvent.click(button);
|
||||
}
|
||||
};
|
||||
|
||||
export const AffineNewPageButton: StoryFn<typeof NewPageButton> = ({
|
||||
...props
|
||||
}) => <NewPageButton {...props} />;
|
||||
AffineNewPageButton.args = {
|
||||
createNewPage: () => toast('Create new page'),
|
||||
createNewEdgeless: () => toast('Create new edgeless'),
|
||||
};
|
||||
|
||||
AffineNewPageButton.play = async ({ canvasElement }) => {
|
||||
const button = canvasElement.querySelector('button') as HTMLButtonElement;
|
||||
expect(button).not.toBeNull();
|
||||
const dropdown = button.querySelector('svg') as SVGSVGElement;
|
||||
expect(dropdown).not.toBeNull();
|
||||
await userEvent.click(dropdown);
|
||||
};
|
||||
|
||||
const testTags = [
|
||||
{
|
||||
color: 'red',
|
||||
id: 'test-tag-id-cccc',
|
||||
value: 'cccccccccccccccc',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
id: 'test-tag-id-a',
|
||||
value: 'a',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
id: 'test-tag-id-b',
|
||||
value: 'b',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
id: 'test-tag-id-c',
|
||||
value: 'c',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
id: 'test-tag-id-d',
|
||||
value: 'd',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
id: 'test-tag-id-0',
|
||||
value: 'foo',
|
||||
},
|
||||
{
|
||||
color: 'pink',
|
||||
id: 'test-tag-id-1',
|
||||
value: 'bar',
|
||||
},
|
||||
{
|
||||
color: 'purple',
|
||||
id: 'test-tag-id-2',
|
||||
value: 'foobar',
|
||||
},
|
||||
{
|
||||
color: 'black',
|
||||
id: 'test-tag-id-3',
|
||||
value: 'affine',
|
||||
},
|
||||
{
|
||||
color: 'orange',
|
||||
id: 'test-tag-id-4',
|
||||
value: 'blocksuite',
|
||||
},
|
||||
{
|
||||
color: 'yellow',
|
||||
id: 'test-tag-id-5',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'green',
|
||||
id: 'test-tag-id-6',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'blue',
|
||||
id: 'test-tag-id-7',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'indigo',
|
||||
id: 'test-tag-id-8',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'teal',
|
||||
id: 'test-tag-id-9',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'cyan',
|
||||
id: 'test-tag-id-10',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'gray',
|
||||
id: 'test-tag-id-11',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
id: 'test-tag-id-12',
|
||||
value: 'toeverything',
|
||||
},
|
||||
];
|
||||
|
||||
export const PageListItemComponent: StoryFn<PageListItemProps> = props => (
|
||||
<PageListItem {...props}></PageListItem>
|
||||
);
|
||||
|
||||
PageListItemComponent.args = {
|
||||
pageId: 'test-page-id',
|
||||
title: 'Test Page Title',
|
||||
preview:
|
||||
'this is page preview and it is very long and will be truncated because it is too long and it is very long and will be truncated because it is too long',
|
||||
icon: <PageIcon />,
|
||||
to: '/hello',
|
||||
selectable: true,
|
||||
createDate: new Date('2021-01-01'),
|
||||
updatedDate: new Date('2023-08-15'),
|
||||
draggable: true,
|
||||
tags: testTags,
|
||||
selected: true,
|
||||
};
|
||||
|
||||
PageListItemComponent.decorators = [withRouter];
|
||||
|
||||
export const ListItemTags: StoryFn<PageTagsProps> = props => (
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||
<div style={{ width: '300px' }}>
|
||||
<PageTags {...props}></PageTags>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
ListItemTags.args = {
|
||||
// FIXME: this is a hack to make the storybook work
|
||||
// tags: testTags,
|
||||
hoverExpandDirection: 'left',
|
||||
widthOnHover: 600,
|
||||
maxItems: 5,
|
||||
};
|
||||
|
||||
export const PageListStory: StoryFn<ListProps<ListItem>> = (
|
||||
props,
|
||||
{ loaded }
|
||||
) => {
|
||||
return (
|
||||
<ListScrollContainer
|
||||
style={{
|
||||
height: '100vh',
|
||||
}}
|
||||
>
|
||||
<List {...props} {...loaded}></List>
|
||||
</ListScrollContainer>
|
||||
);
|
||||
};
|
||||
|
||||
PageListStory.args = {
|
||||
groupBy: [
|
||||
{
|
||||
id: 'all',
|
||||
label: count => `All Pages (${count})`,
|
||||
match: () => true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
PageListStory.argTypes = {
|
||||
selectable: {
|
||||
control: 'radio',
|
||||
options: [true, 'toggle', false],
|
||||
},
|
||||
hideHeader: {
|
||||
type: 'boolean',
|
||||
},
|
||||
};
|
||||
|
||||
async function createAndInitPage(
|
||||
docCollection: DocCollection,
|
||||
title: string,
|
||||
preview: string
|
||||
) {
|
||||
const doc = docCollection.createDoc();
|
||||
initEmptyPage(doc, title);
|
||||
doc.getBlockByFlavour('affine:paragraph').at(0)?.text?.insert(preview, 0);
|
||||
return doc;
|
||||
}
|
||||
|
||||
PageListStory.loaders = [
|
||||
async () => {
|
||||
const schema = new Schema();
|
||||
schema.register(AffineSchemas);
|
||||
const docCollection = new DocCollection({
|
||||
id: 'test-workspace-id',
|
||||
schema,
|
||||
});
|
||||
|
||||
docCollection.meta.setProperties({
|
||||
tags: {
|
||||
options: structuredClone(testTags),
|
||||
},
|
||||
});
|
||||
|
||||
const page1 = await createAndInitPage(
|
||||
docCollection,
|
||||
'This is page 1',
|
||||
'Hello World from page 1'
|
||||
);
|
||||
const page2 = await createAndInitPage(
|
||||
docCollection,
|
||||
'This is page 2',
|
||||
'Hello World from page 2'
|
||||
);
|
||||
const page3 = await createAndInitPage(
|
||||
docCollection,
|
||||
'This is page 3',
|
||||
'Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3'
|
||||
);
|
||||
|
||||
await createAndInitPage(
|
||||
docCollection,
|
||||
'This is page 4',
|
||||
'Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3'
|
||||
);
|
||||
|
||||
page1.meta!.createDate = new Date('2021-01-01').getTime();
|
||||
page2.meta!.createDate = page2.meta!.createDate - 3600 * 1000 * 24;
|
||||
page3.meta!.createDate = page3.meta!.createDate - 3600 * 1000 * 24 * 7;
|
||||
|
||||
docCollection.meta.docMetas[3].tags = testTags.slice(0, 3).map(t => t.id);
|
||||
docCollection.meta.docMetas[2].tags = testTags.slice(0, 12).map(t => t.id);
|
||||
|
||||
return {
|
||||
blockSuiteWorkspace: docCollection,
|
||||
pages: docCollection.meta.docs,
|
||||
};
|
||||
},
|
||||
];
|
||||
|
||||
export const FloatingToolbarStory: StoryFn<typeof FloatingToolbar> = props => {
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: '100vh',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<button
|
||||
style={{
|
||||
border: '1px solid black',
|
||||
padding: '10px',
|
||||
}}
|
||||
onClick={() => setOpen(o => !o)}
|
||||
>
|
||||
{open ? 'hide' : 'show'}
|
||||
</button>
|
||||
<FloatingToolbar
|
||||
style={{ position: 'fixed', bottom: '20px', width: '100%' }}
|
||||
{...props}
|
||||
open={open}
|
||||
>
|
||||
<FloatingToolbar.Item>10 Selected</FloatingToolbar.Item>
|
||||
<FloatingToolbar.Separator />
|
||||
<FloatingToolbar.Button
|
||||
icon={<TagsIcon />}
|
||||
label="Add Tags"
|
||||
onClick={console.log}
|
||||
/>
|
||||
<FloatingToolbar.Button
|
||||
icon={<TagsIcon />}
|
||||
label="Add Tags"
|
||||
onClick={console.log}
|
||||
/>
|
||||
</FloatingToolbar>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,104 +0,0 @@
|
||||
import {
|
||||
registerAffineCreationCommands,
|
||||
registerAffineLayoutCommands,
|
||||
registerAffineSettingsCommands,
|
||||
} from '@affine/core/commands';
|
||||
import { CMDKQuickSearchModal } from '@affine/core/components/pure/cmdk';
|
||||
import { HighlightLabel } from '@affine/core/components/pure/cmdk/highlight';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { Doc } from '@blocksuite/store';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { useStore } from 'jotai';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { withRouter } from 'storybook-addon-react-router-v6';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/QuickSearch',
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
const createMockedPage = () => {
|
||||
return {
|
||||
id: 'test-page',
|
||||
waitForLoaded: () => Promise.resolve(),
|
||||
} as any as Doc;
|
||||
};
|
||||
|
||||
function useRegisterCommands() {
|
||||
const t = useAFFiNEI18N();
|
||||
const store = useStore();
|
||||
useEffect(() => {
|
||||
const unsubs = [
|
||||
registerAffineSettingsCommands({
|
||||
t,
|
||||
store,
|
||||
theme: {
|
||||
setTheme: () => {},
|
||||
theme: 'auto',
|
||||
themes: ['auto', 'dark', 'light'],
|
||||
},
|
||||
languageHelper: {
|
||||
onLanguageChange: () => {},
|
||||
languagesList: [
|
||||
{
|
||||
tag: 'en',
|
||||
name: 'English',
|
||||
originalName: 'English',
|
||||
Completeness: 1,
|
||||
},
|
||||
{
|
||||
tag: 'zh-Hans',
|
||||
name: 'Simplified Chinese',
|
||||
originalName: '简体中文',
|
||||
Completeness: 1,
|
||||
},
|
||||
],
|
||||
currentLanguage: undefined,
|
||||
},
|
||||
editor: null,
|
||||
}),
|
||||
registerAffineCreationCommands({
|
||||
t,
|
||||
store,
|
||||
pageHelper: {
|
||||
createEdgeless: createMockedPage,
|
||||
createPage: createMockedPage,
|
||||
importFile: () => Promise.resolve(),
|
||||
isPreferredEdgeless: () => false,
|
||||
createLinkedPage: createMockedPage,
|
||||
},
|
||||
}),
|
||||
registerAffineLayoutCommands({
|
||||
t,
|
||||
store,
|
||||
}),
|
||||
];
|
||||
|
||||
return () => {
|
||||
unsubs.forEach(unsub => unsub());
|
||||
};
|
||||
}, [store, t]);
|
||||
}
|
||||
|
||||
export const CMDKStoryWithCommands: StoryFn = () => {
|
||||
useRegisterCommands();
|
||||
|
||||
return <CMDKQuickSearchModal open />;
|
||||
};
|
||||
|
||||
CMDKStoryWithCommands.decorators = [withRouter];
|
||||
|
||||
export const HighlightStory: StoryFn = () => {
|
||||
const [query, setQuery] = useState('');
|
||||
const label = {
|
||||
title: 'title',
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<input value={query} onChange={e => setQuery(e.target.value)} />
|
||||
<HighlightLabel label={label} highlight={query} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { CMDKContainer, CMDKModal } from '@affine/core/components/pure/cmdk';
|
||||
import { useCMDKCommandGroups } from '@affine/core/components/pure/cmdk/data-hooks';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/QuickSearch',
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
export const CMDKModalStory: StoryFn = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [counter, setCounter] = useState(0);
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => setOpen(true)}>Open Modal</Button>
|
||||
<CMDKModal key={counter} open={open} onOpenChange={setOpen}>
|
||||
<Button onClick={() => setCounter(c => c + 1)}>
|
||||
Trigger new modal
|
||||
</Button>
|
||||
</CMDKModal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const CMDKPanelStory: StoryFn = () => {
|
||||
const [query, setQuery] = useState('');
|
||||
const groups = useCMDKCommandGroups();
|
||||
return (
|
||||
<CMDKModal open>
|
||||
<CMDKContainer
|
||||
open
|
||||
query={query}
|
||||
onQueryChange={setQuery}
|
||||
groups={groups}
|
||||
/>
|
||||
</CMDKModal>
|
||||
);
|
||||
};
|
||||
@@ -1,113 +0,0 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { PublicLinkDisableModal } from '@affine/component/disable-public-link';
|
||||
import { ShareMenu } from '@affine/core/components/affine/share-page-modal/share-menu';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import type { Doc } from '@blocksuite/store';
|
||||
import { expect } from '@storybook/jest';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import {
|
||||
initEmptyPage,
|
||||
useService,
|
||||
WorkspaceService,
|
||||
} from '@toeverything/infra';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/ShareMenu',
|
||||
component: ShareMenu,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
async function unimplemented() {
|
||||
toast('work in progress');
|
||||
}
|
||||
|
||||
export const Basic: StoryFn = () => {
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
|
||||
const [page, setPage] = useState<Doc | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const page = workspace.docCollection.createDoc({ id: nanoid() });
|
||||
initEmptyPage(page);
|
||||
|
||||
setPage(page);
|
||||
}, [workspace]);
|
||||
|
||||
if (!page) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<ShareMenu
|
||||
currentPage={page}
|
||||
workspaceMetadata={workspace}
|
||||
onEnableAffineCloud={unimplemented}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Basic.play = async ({ canvasElement }) => {
|
||||
{
|
||||
const button = canvasElement.querySelector(
|
||||
'[data-testid="share-menu-button"]'
|
||||
) as HTMLButtonElement;
|
||||
expect(button).not.toBeNull();
|
||||
button.click();
|
||||
}
|
||||
await new Promise(resolve => window.setTimeout(resolve, 100));
|
||||
{
|
||||
const button = canvasElement.querySelector(
|
||||
'[data-testid="share-menu-enable-affine-cloud-button"]'
|
||||
);
|
||||
expect(button).not.toBeNull();
|
||||
}
|
||||
};
|
||||
|
||||
export const AffineBasic: StoryFn = () => {
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
|
||||
const [page, setPage] = useState<Doc | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const page = workspace.docCollection.createDoc({ id: nanoid() });
|
||||
initEmptyPage(page);
|
||||
|
||||
setPage(page);
|
||||
}, [workspace]);
|
||||
|
||||
if (!page) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<ShareMenu
|
||||
currentPage={page}
|
||||
workspaceMetadata={{
|
||||
...workspace.meta,
|
||||
flavour: WorkspaceFlavour.AFFINE_CLOUD,
|
||||
}}
|
||||
onEnableAffineCloud={unimplemented}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const DisableModal: StoryFn = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<div onClick={() => setOpen(!open)}>Disable Public Link</div>
|
||||
<PublicLinkDisableModal
|
||||
open={open}
|
||||
onConfirm={() => {
|
||||
toast('Disabled');
|
||||
setOpen(false);
|
||||
}}
|
||||
onOpenChange={setOpen}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
/* deepscan-disable USELESS_ARROW_FUNC_BIND */
|
||||
import { Switch } from '@affine/component';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/Switch',
|
||||
component: Switch,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
export const Basic: StoryFn = () => {
|
||||
return <Switch>Switch</Switch>;
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
import type { WorkspaceListProps } from '@affine/component/workspace-list';
|
||||
import { WorkspaceList } from '@affine/component/workspace-list';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import {
|
||||
useLiveData,
|
||||
useService,
|
||||
WorkspacesService,
|
||||
} from '@toeverything/infra';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/WorkspaceList',
|
||||
component: WorkspaceList,
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta<WorkspaceListProps>;
|
||||
|
||||
export const Default = () => {
|
||||
const list = useLiveData(useService(WorkspacesService).list.workspaces$);
|
||||
return (
|
||||
<WorkspaceList
|
||||
currentWorkspaceId={null}
|
||||
items={list}
|
||||
onClick={() => {}}
|
||||
onSettingClick={() => {}}
|
||||
onDragEnd={_ => {}}
|
||||
useWorkspaceAvatar={() => undefined}
|
||||
useWorkspaceName={() => undefined}
|
||||
useIsWorkspaceOwner={() => false}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["./src/**/*", "./.storybook/**/*"],
|
||||
"compilerOptions": {
|
||||
// Workaround for storybook build
|
||||
"baseUrl": "../..",
|
||||
"composite": true,
|
||||
"noEmit": false,
|
||||
"outDir": "lib"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "../../packages/frontend/core"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/frontend/component"
|
||||
},
|
||||
{
|
||||
"path": "../../tools/cli"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/common/env"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/common/infra"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"jsx": "react-jsx",
|
||||
"moduleResolution": "bundler",
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"noEmit": false,
|
||||
"outDir": "lib/.storybook"
|
||||
},
|
||||
"include": [".storybook"],
|
||||
"exclude": ["lib"],
|
||||
"references": [
|
||||
{ "path": "../../packages/frontend/core" },
|
||||
{ "path": "../../packages/frontend/i18n" },
|
||||
{
|
||||
"path": "../../packages/common/env"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/frontend/core/tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -126,9 +126,6 @@
|
||||
{
|
||||
"path": "./tests/kit"
|
||||
},
|
||||
{
|
||||
"path": "./tests/storybook"
|
||||
},
|
||||
{
|
||||
"path": "./tests/affine-local"
|
||||
},
|
||||
|
||||
213
yarn.lock
213
yarn.lock
@@ -764,61 +764,6 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@affine/storybook@workspace:tests/storybook":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@affine/storybook@workspace:tests/storybook"
|
||||
dependencies:
|
||||
"@affine/cli": "workspace:*"
|
||||
"@affine/component": "workspace:*"
|
||||
"@affine/i18n": "workspace:*"
|
||||
"@blocksuite/block-std": "npm:0.14.0-canary-202404151235-655ec84"
|
||||
"@blocksuite/blocks": "npm:0.14.0-canary-202404151235-655ec84"
|
||||
"@blocksuite/global": "npm:0.14.0-canary-202404151235-655ec84"
|
||||
"@blocksuite/icons": "npm:2.1.46"
|
||||
"@blocksuite/inline": "npm:0.14.0-canary-202404151235-655ec84"
|
||||
"@blocksuite/presets": "npm:0.14.0-canary-202404151235-655ec84"
|
||||
"@blocksuite/store": "npm:0.14.0-canary-202404151235-655ec84"
|
||||
"@dnd-kit/sortable": "npm:^8.0.0"
|
||||
"@storybook/addon-actions": "npm:^7.6.17"
|
||||
"@storybook/addon-essentials": "npm:^7.6.17"
|
||||
"@storybook/addon-interactions": "npm:^7.6.17"
|
||||
"@storybook/addon-links": "npm:^7.6.17"
|
||||
"@storybook/addon-storysource": "npm:^7.6.17"
|
||||
"@storybook/blocks": "npm:^7.6.17"
|
||||
"@storybook/builder-vite": "npm:^7.6.17"
|
||||
"@storybook/jest": "npm:^0.2.3"
|
||||
"@storybook/react": "npm:^7.6.17"
|
||||
"@storybook/react-vite": "npm:^7.6.17"
|
||||
"@storybook/test-runner": "npm:^0.17.0"
|
||||
"@storybook/testing-library": "npm:^0.2.2"
|
||||
"@vanilla-extract/esbuild-plugin": "npm:^2.3.5"
|
||||
"@vitejs/plugin-react": "npm:^4.2.1"
|
||||
chromatic: "npm:^11.3.0"
|
||||
concurrently: "npm:^8.2.2"
|
||||
foxact: "npm:^0.2.33"
|
||||
jest-mock: "npm:^29.7.0"
|
||||
jotai: "npm:^2.8.0"
|
||||
lodash-es: "npm:^4.17.21"
|
||||
nanoid: "npm:^5.0.7"
|
||||
react: "npm:18.2.0"
|
||||
react-dom: "npm:18.2.0"
|
||||
react-router-dom: "npm:^6.22.3"
|
||||
serve: "npm:^14.2.1"
|
||||
ses: "npm:^1.4.1"
|
||||
storybook: "npm:^7.6.17"
|
||||
storybook-addon-react-router-v6: "npm:^2.0.15"
|
||||
storybook-dark-mode: "npm:^3.0.3"
|
||||
storybook-mock-date-decorator: "npm:^1.0.2"
|
||||
wait-on: "npm:^7.2.0"
|
||||
peerDependencies:
|
||||
"@blocksuite/blocks": "*"
|
||||
"@blocksuite/global": "*"
|
||||
"@blocksuite/icons": 2.1.34
|
||||
"@blocksuite/presets": "*"
|
||||
"@blocksuite/store": "*"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@affine/templates@workspace:*, @affine/templates@workspace:packages/frontend/templates":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@affine/templates@workspace:packages/frontend/templates"
|
||||
@@ -2245,7 +2190,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.14.0, @babel/core@npm:^7.18.5, @babel/core@npm:^7.18.9, @babel/core@npm:^7.20.12, @babel/core@npm:^7.22.5, @babel/core@npm:^7.22.9, @babel/core@npm:^7.23.0, @babel/core@npm:^7.23.2, @babel/core@npm:^7.23.5, @babel/core@npm:^7.23.9, @babel/core@npm:^7.7.5":
|
||||
"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.14.0, @babel/core@npm:^7.18.5, @babel/core@npm:^7.18.9, @babel/core@npm:^7.20.12, @babel/core@npm:^7.22.5, @babel/core@npm:^7.22.9, @babel/core@npm:^7.23.0, @babel/core@npm:^7.23.2, @babel/core@npm:^7.23.9, @babel/core@npm:^7.7.5":
|
||||
version: 7.24.3
|
||||
resolution: "@babel/core@npm:7.24.3"
|
||||
dependencies:
|
||||
@@ -3368,7 +3313,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self@npm:^7.18.6, @babel/plugin-transform-react-jsx-self@npm:^7.23.3":
|
||||
"@babel/plugin-transform-react-jsx-self@npm:^7.18.6":
|
||||
version: 7.23.3
|
||||
resolution: "@babel/plugin-transform-react-jsx-self@npm:7.23.3"
|
||||
dependencies:
|
||||
@@ -3379,7 +3324,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/plugin-transform-react-jsx-source@npm:^7.19.6, @babel/plugin-transform-react-jsx-source@npm:^7.23.3":
|
||||
"@babel/plugin-transform-react-jsx-source@npm:^7.19.6":
|
||||
version: 7.23.3
|
||||
resolution: "@babel/plugin-transform-react-jsx-source@npm:7.23.3"
|
||||
dependencies:
|
||||
@@ -3714,7 +3659,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2":
|
||||
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2":
|
||||
version: 7.23.9
|
||||
resolution: "@babel/runtime@npm:7.23.9"
|
||||
dependencies:
|
||||
@@ -14437,7 +14382,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.18.0, @types/babel__core@npm:^7.20.5":
|
||||
"@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.18.0":
|
||||
version: 7.20.5
|
||||
resolution: "@types/babel__core@npm:7.20.5"
|
||||
dependencies:
|
||||
@@ -15747,20 +15692,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vanilla-extract/esbuild-plugin@npm:^2.3.5":
|
||||
version: 2.3.5
|
||||
resolution: "@vanilla-extract/esbuild-plugin@npm:2.3.5"
|
||||
dependencies:
|
||||
"@vanilla-extract/integration": "npm:^7.0.0"
|
||||
peerDependencies:
|
||||
esbuild: ">=0.17.6"
|
||||
peerDependenciesMeta:
|
||||
esbuild:
|
||||
optional: true
|
||||
checksum: 10/5ef46dc86a3121a2f1bfa6758511cc16a1dda434d6faa0d4cae278bcd83c9d1f577abc476dfa75442ffcadd477af30d58ce1f3582ddf4ba2198eecff828cada6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vanilla-extract/integration@npm:^7.0.0, @vanilla-extract/integration@npm:^7.1.2":
|
||||
version: 7.1.2
|
||||
resolution: "@vanilla-extract/integration@npm:7.1.2"
|
||||
@@ -15862,21 +15793,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitejs/plugin-react@npm:^4.2.1":
|
||||
version: 4.2.1
|
||||
resolution: "@vitejs/plugin-react@npm:4.2.1"
|
||||
dependencies:
|
||||
"@babel/core": "npm:^7.23.5"
|
||||
"@babel/plugin-transform-react-jsx-self": "npm:^7.23.3"
|
||||
"@babel/plugin-transform-react-jsx-source": "npm:^7.23.3"
|
||||
"@types/babel__core": "npm:^7.20.5"
|
||||
react-refresh: "npm:^0.14.0"
|
||||
peerDependencies:
|
||||
vite: ^4.2.0 || ^5.0.0
|
||||
checksum: 10/d7fa6dacd3c246bcee482ff4b7037b2978b6ca002b79780ad4921e91ae4bc85ab234cfb94f8d4d825fed8488a0acdda2ff02b47c27b3055187c0727b18fc725e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/coverage-istanbul@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@vitest/coverage-istanbul@npm:1.4.0"
|
||||
@@ -18446,25 +18362,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chromatic@npm:^11.3.0":
|
||||
version: 11.3.0
|
||||
resolution: "chromatic@npm:11.3.0"
|
||||
peerDependencies:
|
||||
"@chromatic-com/cypress": ^0.*.* || ^1.0.0
|
||||
"@chromatic-com/playwright": ^0.*.* || ^1.0.0
|
||||
peerDependenciesMeta:
|
||||
"@chromatic-com/cypress":
|
||||
optional: true
|
||||
"@chromatic-com/playwright":
|
||||
optional: true
|
||||
bin:
|
||||
chroma: dist/bin.js
|
||||
chromatic: dist/bin.js
|
||||
chromatic-cli: dist/bin.js
|
||||
checksum: 10/fd8d0678c93bebe45cf087496a8b4c44967d06003bc26f18d7b5ce25db00962efd7fbb700f098f3196f1d65b037050ca785da0e07bfc1766ed81b2f9bbbad23f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chrome-trace-event@npm:^1.0.2, chrome-trace-event@npm:^1.0.3":
|
||||
version: 1.0.3
|
||||
resolution: "chrome-trace-event@npm:1.0.3"
|
||||
@@ -19023,13 +18920,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"compare-versions@npm:^6.0.0":
|
||||
version: 6.1.0
|
||||
resolution: "compare-versions@npm:6.1.0"
|
||||
checksum: 10/20f349e7f8ad784704c68265f4e660e2abbe2c3d5c75793184fccb85f0c5c0263260e01fdd4488376f6b74b0f069e16c9684463f7316b075716fb1581eb36b77
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"component-emitter@npm:^1.3.0":
|
||||
version: 1.3.1
|
||||
resolution: "component-emitter@npm:1.3.1"
|
||||
@@ -19103,26 +18993,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"concurrently@npm:^8.2.2":
|
||||
version: 8.2.2
|
||||
resolution: "concurrently@npm:8.2.2"
|
||||
dependencies:
|
||||
chalk: "npm:^4.1.2"
|
||||
date-fns: "npm:^2.30.0"
|
||||
lodash: "npm:^4.17.21"
|
||||
rxjs: "npm:^7.8.1"
|
||||
shell-quote: "npm:^1.8.1"
|
||||
spawn-command: "npm:0.0.2"
|
||||
supports-color: "npm:^8.1.1"
|
||||
tree-kill: "npm:^1.2.2"
|
||||
yargs: "npm:^17.7.2"
|
||||
bin:
|
||||
conc: dist/bin/concurrently.js
|
||||
concurrently: dist/bin/concurrently.js
|
||||
checksum: 10/dcb1aa69d9c611a7bda9d4fc0fe1e388f971d1744acec7e0d52dffa2ef55743f1266ec9292f414c5789b9f61734b3fce772bd005d4de9564a949fb121b97bae1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"config-file-ts@npm:^0.2.4":
|
||||
version: 0.2.6
|
||||
resolution: "config-file-ts@npm:0.2.6"
|
||||
@@ -19842,15 +19712,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"date-fns@npm:^2.30.0":
|
||||
version: 2.30.0
|
||||
resolution: "date-fns@npm:2.30.0"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.21.0"
|
||||
checksum: 10/70b3e8ea7aaaaeaa2cd80bd889622a4bcb5d8028b4de9162cbcda359db06e16ff6e9309e54eead5341e71031818497f19aaf9839c87d1aba1e27bb4796e758a9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"date-fns@npm:^3.6.0":
|
||||
version: 3.6.0
|
||||
resolution: "date-fns@npm:3.6.0"
|
||||
@@ -29012,13 +28873,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mockdate@npm:^3.0.5":
|
||||
version: 3.0.5
|
||||
resolution: "mockdate@npm:3.0.5"
|
||||
checksum: 10/ff74f43f56a12e1339e838aee623e37b6e4c378173905697f2a006a5c581eea9c71da54fcea76c27e7e744422e49395c668932bf09e67f024841240ffef91fd2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"modern-ahocorasick@npm:^1.0.0":
|
||||
version: 1.0.1
|
||||
resolution: "modern-ahocorasick@npm:1.0.1"
|
||||
@@ -31864,15 +31718,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-inspector@npm:6.0.2":
|
||||
version: 6.0.2
|
||||
resolution: "react-inspector@npm:6.0.2"
|
||||
peerDependencies:
|
||||
react: ^16.8.4 || ^17.0.0 || ^18.0.0
|
||||
checksum: 10/5d23ad0f6f920458abd4c01af1b3cbdbe8846c254762fd6cfff4df119c54e08dd98ce8e91acacafb8173c19f07de2066df5b8e6cb19425751c1929a2620cbe77
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-is@npm:18.1.0":
|
||||
version: 18.1.0
|
||||
resolution: "react-is@npm:18.1.0"
|
||||
@@ -33873,13 +33718,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"spawn-command@npm:0.0.2":
|
||||
version: 0.0.2
|
||||
resolution: "spawn-command@npm:0.0.2"
|
||||
checksum: 10/f13e8c3c63abd4a0b52fb567eba5f7940d480c5ed3ec61781d38a1850f179b1196c39e6efa2bbd301f82c1bf1cd7807abc8fbd8fc8e44bcaa3975a124c0d1657
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"spawn-wrap@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "spawn-wrap@npm:2.0.0"
|
||||
@@ -34134,32 +33972,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"storybook-addon-react-router-v6@npm:^2.0.15":
|
||||
version: 2.0.15
|
||||
resolution: "storybook-addon-react-router-v6@npm:2.0.15"
|
||||
dependencies:
|
||||
compare-versions: "npm:^6.0.0"
|
||||
react-inspector: "npm:6.0.2"
|
||||
peerDependencies:
|
||||
"@storybook/blocks": ^7.0.0
|
||||
"@storybook/channels": ^7.0.0
|
||||
"@storybook/components": ^7.0.0
|
||||
"@storybook/core-events": ^7.0.0
|
||||
"@storybook/manager-api": ^7.0.0
|
||||
"@storybook/preview-api": ^7.0.0
|
||||
"@storybook/theming": ^7.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-router-dom: ^6.4.0
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
checksum: 10/a6fbebd0f9b44b2866920c61d40e591adf6dc1fcd058814f349a78cded41c239e8f08448edec747b660476d55c44623caadef2b2de90321279debe60bafba4b9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"storybook-dark-mode@npm:^3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "storybook-dark-mode@npm:3.0.3"
|
||||
@@ -34184,17 +33996,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"storybook-mock-date-decorator@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "storybook-mock-date-decorator@npm:1.0.2"
|
||||
dependencies:
|
||||
mockdate: "npm:^3.0.5"
|
||||
peerDependencies:
|
||||
"@storybook/addons": ">=6"
|
||||
checksum: 10/c8e8b6966b58bd830c4837e6940328b9d32776c216bfcbc9f55bb38c5c192ab511670ff77505577737589bf83a7ad98538da1e62a2aa9c628e42e5998f2f6147
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"storybook@npm:^7.6.17":
|
||||
version: 7.6.17
|
||||
resolution: "storybook@npm:7.6.17"
|
||||
@@ -34650,7 +34451,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"supports-color@npm:^8.0.0, supports-color@npm:^8.1.1, supports-color@npm:~8.1.1":
|
||||
"supports-color@npm:^8.0.0, supports-color@npm:~8.1.1":
|
||||
version: 8.1.1
|
||||
resolution: "supports-color@npm:8.1.1"
|
||||
dependencies:
|
||||
@@ -36735,7 +36536,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"wait-on@npm:^7.0.0, wait-on@npm:^7.2.0":
|
||||
"wait-on@npm:^7.0.0":
|
||||
version: 7.2.0
|
||||
resolution: "wait-on@npm:7.2.0"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user