mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-23 00:41:50 +03:00
Merge branch 'develop' into feat/doublelink
This commit is contained in:
commit
63634e2057
@ -1,12 +1,12 @@
|
||||
import { useState } from 'react';
|
||||
import { CreateView } from '@toeverything/framework/virgo';
|
||||
import {
|
||||
BlockPendantProvider,
|
||||
useOnSelect,
|
||||
} from '@toeverything/components/editor-core';
|
||||
import { Upload } from '../../components/upload/upload';
|
||||
import { CreateView } from '@toeverything/framework/virgo';
|
||||
import { useState } from 'react';
|
||||
import { SourceView } from '../../components/source-view';
|
||||
import { LinkContainer } from '../../components/style-container';
|
||||
import { Upload } from '../../components/upload/upload';
|
||||
|
||||
const MESSAGES = {
|
||||
ADD_EMBED_LINK: 'Add embed link',
|
||||
@ -38,7 +38,6 @@ export const EmbedLinkView = (props: EmbedLinkView) => {
|
||||
{embedLinkUrl ? (
|
||||
<SourceView
|
||||
block={block}
|
||||
editorElement={props.editorElement}
|
||||
isSelected={isSelect}
|
||||
viewType="embedLink"
|
||||
link={embedLinkUrl}
|
||||
|
@ -1,11 +1,18 @@
|
||||
import type { KanbanCard } from '@toeverything/components/editor-core';
|
||||
import {
|
||||
KanbanCard,
|
||||
RenderBlock,
|
||||
useEditor,
|
||||
useKanban,
|
||||
useRefPage,
|
||||
} from '@toeverything/components/editor-core';
|
||||
import { styled } from '@toeverything/components/ui';
|
||||
import { PenIcon } from '@toeverything/components/icons';
|
||||
import {
|
||||
IconButton,
|
||||
MuiClickAwayListener,
|
||||
styled,
|
||||
} from '@toeverything/components/ui';
|
||||
import { useFlag } from '@toeverything/datasource/feature-flags';
|
||||
import { useState, type MouseEvent } from 'react';
|
||||
import { useRefPage } from './RefPage';
|
||||
|
||||
const CardContent = styled('div')({
|
||||
margin: '20px',
|
||||
@ -23,6 +30,7 @@ const CardActions = styled('div')({
|
||||
fontWeight: '300',
|
||||
color: '#98ACBD',
|
||||
transition: 'all ease-in 0.2s',
|
||||
zIndex: 1,
|
||||
|
||||
':hover': {
|
||||
background: '#F5F7F8',
|
||||
@ -39,11 +47,13 @@ const PlusIcon = styled('div')({
|
||||
});
|
||||
|
||||
const CardContainer = styled('div')({
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
backgroundColor: '#fff',
|
||||
border: '1px solid #E2E7ED',
|
||||
borderRadius: '5px',
|
||||
overflow: 'hidden',
|
||||
|
||||
[CardActions.toString()]: {
|
||||
opacity: '0',
|
||||
@ -55,6 +65,23 @@ const CardContainer = styled('div')({
|
||||
},
|
||||
});
|
||||
|
||||
const Overlay = styled('div')({
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
background: 'transparent',
|
||||
|
||||
'& > *': {
|
||||
visibility: 'hidden',
|
||||
position: 'absolute',
|
||||
right: '24px',
|
||||
top: '16px',
|
||||
},
|
||||
'&:hover > *': {
|
||||
visibility: 'visible',
|
||||
},
|
||||
});
|
||||
|
||||
export const CardItem = ({
|
||||
id,
|
||||
block,
|
||||
@ -64,24 +91,43 @@ export const CardItem = ({
|
||||
}) => {
|
||||
const { addSubItem } = useKanban();
|
||||
const { openSubPage } = useRefPage();
|
||||
const [editable, setEditable] = useState(false);
|
||||
const showKanbanRefPageFlag = useFlag('ShowKanbanRefPage', false);
|
||||
const { editor } = useEditor();
|
||||
|
||||
const onAddItem = async () => {
|
||||
setEditable(true);
|
||||
await addSubItem(block);
|
||||
};
|
||||
|
||||
const onClickCard = async () => {
|
||||
showKanbanRefPageFlag && openSubPage(id);
|
||||
openSubPage(id);
|
||||
};
|
||||
|
||||
const onClickPen = (e: MouseEvent<Element>) => {
|
||||
e.stopPropagation();
|
||||
setEditable(true);
|
||||
editor.selectionManager.activeNodeByNodeId(block.id);
|
||||
};
|
||||
|
||||
return (
|
||||
<CardContainer onClick={onClickCard}>
|
||||
<CardContent>
|
||||
<RenderBlock blockId={id} />
|
||||
</CardContent>
|
||||
<CardActions onClick={onAddItem}>
|
||||
<PlusIcon />
|
||||
<span>Add a sub-block</span>
|
||||
</CardActions>
|
||||
</CardContainer>
|
||||
<MuiClickAwayListener onClickAway={() => setEditable(false)}>
|
||||
<CardContainer>
|
||||
<CardContent>
|
||||
<RenderBlock blockId={id} />
|
||||
</CardContent>
|
||||
{showKanbanRefPageFlag && !editable && (
|
||||
<Overlay onClick={onClickCard}>
|
||||
<IconButton backgroundColor="#fff" onClick={onClickPen}>
|
||||
<PenIcon />
|
||||
</IconButton>
|
||||
</Overlay>
|
||||
)}
|
||||
<CardActions onClick={onAddItem}>
|
||||
<PlusIcon />
|
||||
<span>Add a sub-block</span>
|
||||
</CardActions>
|
||||
</CardContainer>
|
||||
</MuiClickAwayListener>
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useEditor } from '@toeverything/components/editor-core';
|
||||
import { MuiBackdrop, styled, useTheme } from '@toeverything/components/ui';
|
||||
import { createContext, ReactNode, useContext, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { RenderBlock } from '../render-block';
|
||||
|
||||
const Dialog = styled('div')({
|
||||
flex: 1,
|
||||
@ -30,7 +30,7 @@ const Modal = ({ open, children }: { open: boolean; children?: ReactNode }) => {
|
||||
onClick={closeSubPage}
|
||||
>
|
||||
<Dialog
|
||||
onClick={e => {
|
||||
onClick={(e: { stopPropagation: () => void }) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
@ -43,9 +43,21 @@ const Modal = ({ open, children }: { open: boolean; children?: ReactNode }) => {
|
||||
};
|
||||
|
||||
const ModalPage = ({ blockId }: { blockId: string | null }) => {
|
||||
const { editor, editorElement } = useEditor();
|
||||
|
||||
const AffineEditor = editorElement as any;
|
||||
|
||||
return (
|
||||
<Modal open={!!blockId}>
|
||||
{blockId && <RenderBlock blockId={blockId} />}
|
||||
{blockId && (
|
||||
<AffineEditor
|
||||
workspace={editor.workspace}
|
||||
rootBlockId={blockId}
|
||||
scrollBlank={false}
|
||||
// use edgeless mode prevent padding and blank bottom
|
||||
isEdgeless
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
};
|
@ -4,30 +4,33 @@ import { SceneKanbanContext } from './context';
|
||||
import { CardContainerWrapper } from './dndable/wrapper/CardContainerWrapper';
|
||||
import type { ComponentType } from 'react';
|
||||
import type { CreateView } from '@toeverything/framework/virgo';
|
||||
import { RefPageProvider } from './RefPage';
|
||||
|
||||
export const SceneKanban: ComponentType<CreateView> = withKanban<CreateView>(
|
||||
({ editor, block }) => {
|
||||
const { kanban } = useKanban();
|
||||
|
||||
return (
|
||||
<SceneKanbanContext.Provider value={{ editor, block }}>
|
||||
<CardContainerWrapper
|
||||
dataSource={kanban}
|
||||
render={({
|
||||
activeId,
|
||||
items,
|
||||
containerIds,
|
||||
isSortingContainer,
|
||||
}) => (
|
||||
<CardContainer
|
||||
activeId={activeId}
|
||||
items={items}
|
||||
isSortingContainer={isSortingContainer}
|
||||
containerIds={containerIds}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</SceneKanbanContext.Provider>
|
||||
<RefPageProvider>
|
||||
<SceneKanbanContext.Provider value={{ editor, block }}>
|
||||
<CardContainerWrapper
|
||||
dataSource={kanban}
|
||||
render={({
|
||||
activeId,
|
||||
items,
|
||||
containerIds,
|
||||
isSortingContainer,
|
||||
}) => (
|
||||
<CardContainer
|
||||
activeId={activeId}
|
||||
items={items}
|
||||
isSortingContainer={isSortingContainer}
|
||||
containerIds={containerIds}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</SceneKanbanContext.Provider>
|
||||
</RefPageProvider>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { memo, useEffect, useRef, useState } from 'react';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { memo, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { StyledBlockPreview } from '@toeverything/components/common';
|
||||
import { AsyncBlock, useEditor } from '@toeverything/components/editor-core';
|
||||
import { services } from '@toeverything/datasource/db-service';
|
||||
import { AsyncBlock } from '@toeverything/framework/virgo';
|
||||
import { debounce, sleep } from '@toeverything/utils';
|
||||
|
||||
const updateTitle = async (
|
||||
@ -73,15 +73,15 @@ const useBlockTitle = (block: AsyncBlock, blockId: string) => {
|
||||
type BlockPreviewProps = {
|
||||
block: AsyncBlock;
|
||||
blockId: string;
|
||||
editorElement?: () => JSX.Element;
|
||||
};
|
||||
|
||||
const InternalBlockPreview = (props: BlockPreviewProps) => {
|
||||
const container = useRef<HTMLDivElement>();
|
||||
const [preview, setPreview] = useState(true);
|
||||
const title = useBlockTitle(props.block, props.blockId);
|
||||
const { editorElement } = useEditor();
|
||||
|
||||
const AffineEditor = props.editorElement as any;
|
||||
const AffineEditor = editorElement as any;
|
||||
|
||||
useEffect(() => {
|
||||
if (container?.current) {
|
||||
|
@ -1,17 +1,15 @@
|
||||
import {
|
||||
AsyncBlock,
|
||||
useCurrentView,
|
||||
useLazyIframe,
|
||||
} from '@toeverything/components/editor-core';
|
||||
import { styled } from '@toeverything/components/ui';
|
||||
import { ReactElement, ReactNode, useEffect, useRef, useState } from 'react';
|
||||
import { ReactNode, useEffect, useRef, useState } from 'react';
|
||||
import { SCENE_CONFIG } from '../../blocks/group/config';
|
||||
import { BlockPreview } from './BlockView';
|
||||
import { formatUrl } from './format-url';
|
||||
|
||||
export interface Props {
|
||||
block: AsyncBlock;
|
||||
editorElement?: () => JSX.Element;
|
||||
viewType?: string;
|
||||
link: string;
|
||||
// onResizeEnd: (data: any) => void;
|
||||
@ -150,7 +148,7 @@ const LoadingContiner = () => {
|
||||
};
|
||||
|
||||
export const SourceView = (props: Props) => {
|
||||
const { link, isSelected, block, editorElement } = props;
|
||||
const { link, isSelected, block } = props;
|
||||
const src = formatUrl(link);
|
||||
// let iframeShow = useLazyIframe(src, 3000, iframeContainer);
|
||||
const [currentView] = useCurrentView();
|
||||
@ -161,10 +159,7 @@ export const SourceView = (props: Props) => {
|
||||
<SourceViewContainer isSelected={isSelected} scene={type}>
|
||||
<MouseMaskContainer />
|
||||
|
||||
<LazyIframe
|
||||
src={src}
|
||||
fallback={LoadingContiner()}
|
||||
></LazyIframe>
|
||||
<LazyIframe src={src} fallback={LoadingContiner()} />
|
||||
</SourceViewContainer>
|
||||
</div>
|
||||
);
|
||||
@ -175,11 +170,7 @@ export const SourceView = (props: Props) => {
|
||||
style={{ padding: '0' }}
|
||||
scene={type}
|
||||
>
|
||||
<BlockPreview
|
||||
block={block}
|
||||
editorElement={editorElement}
|
||||
blockId={src}
|
||||
/>
|
||||
<BlockPreview block={block} blockId={src} />
|
||||
</SourceViewContainer>
|
||||
);
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ import { SelectBlock } from '../selection';
|
||||
export interface CreateView {
|
||||
block: AsyncBlock;
|
||||
editor: Editor;
|
||||
editorElement: () => JSX.Element;
|
||||
/**
|
||||
* @deprecated Use recast table instead
|
||||
*/
|
||||
|
@ -16,4 +16,4 @@ export * from './utils';
|
||||
|
||||
export * from './editor';
|
||||
|
||||
export { RefPageProvider, useRefPage } from './ref-page';
|
||||
export { useEditor } from './Contexts';
|
||||
|
@ -2,7 +2,6 @@ import { Protocol } from '@toeverything/datasource/db-service';
|
||||
import { AsyncBlock } from '../editor';
|
||||
import { ComponentType, createContext, ReactNode, useContext } from 'react';
|
||||
import { RecastBlock } from './types';
|
||||
import { RefPageProvider } from '../ref-page';
|
||||
|
||||
/**
|
||||
* Determine whether the block supports RecastBlock
|
||||
@ -48,7 +47,7 @@ export const RecastBlockProvider = ({
|
||||
|
||||
return (
|
||||
<RecastBlockContext.Provider value={block}>
|
||||
<RefPageProvider>{children}</RefPageProvider>
|
||||
{children}
|
||||
</RecastBlockContext.Provider>
|
||||
);
|
||||
};
|
||||
|
@ -1 +0,0 @@
|
||||
export { useRefPage, RefPageProvider } from './ModalPage';
|
@ -13,7 +13,7 @@ export function RenderBlock({
|
||||
blockId,
|
||||
hasContainer = true,
|
||||
}: RenderBlockProps) {
|
||||
const { editor, editorElement } = useEditor();
|
||||
const { editor } = useEditor();
|
||||
const { block } = useBlock(blockId);
|
||||
|
||||
const setRef = useCallback(
|
||||
@ -50,7 +50,6 @@ export function RenderBlock({
|
||||
block={block}
|
||||
columns={columns.columns}
|
||||
columnsFromId={columns.fromId}
|
||||
editorElement={editorElement}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -21,7 +21,7 @@ export const plugins: PluginCreator[] = [
|
||||
CommandMenuPlugin,
|
||||
DoubleLinkMenuPlugin,
|
||||
TemplatePlugin,
|
||||
SelectionGroupPlugin,
|
||||
// SelectionGroupPlugin,
|
||||
AddCommentPlugin,
|
||||
GroupMenuPlugin,
|
||||
];
|
||||
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"executors": {
|
||||
"svgOptimize": {
|
||||
"implementation": "./svgo.js",
|
||||
"schema": "./schema.json",
|
||||
"description": "Run `svgo` (to optimize svg)."
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"executors": "./executor.json"
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"type": "object",
|
||||
"cli": "nx",
|
||||
"properties": {
|
||||
"svgOptimize": {
|
||||
"type": "string",
|
||||
"description": "optimize svg"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
const path = require('path');
|
||||
const svgo = require('svgo');
|
||||
const { readdir, readFile, writeFile, exists } = require('fs/promises');
|
||||
const { pascalCase, paramCase } = require('change-case');
|
||||
const svgr = require('@svgr/core');
|
||||
|
||||
async function optimizeSvg(folder) {
|
||||
try {
|
||||
const icons = await readdir(folder);
|
||||
const generateIcons = icons
|
||||
.filter(n => n.endsWith('.svg'))
|
||||
.map(async icon => {
|
||||
let originSvg;
|
||||
try {
|
||||
originSvg = await readFile(path.resolve(folder, icon));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
let optimizedSvg;
|
||||
try {
|
||||
const data = optimize(originSvg);
|
||||
optimizedSvg = data.data;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
const JSXContent = await getJSXContent(
|
||||
pascalCase(icon),
|
||||
optimizedSvg
|
||||
);
|
||||
|
||||
const iconName = path.basename(icon, '.svg');
|
||||
await writeFile(
|
||||
path.resolve(folder, `${iconName}.tsx`),
|
||||
JSXContent,
|
||||
{ encoding: 'utf8', flag: '' }
|
||||
);
|
||||
|
||||
console.log('Generated:', iconName);
|
||||
});
|
||||
|
||||
await Promise.allSettled([
|
||||
...generateIcons,
|
||||
generateImportEntry(icons, folder),
|
||||
]);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
function optimize(input) {
|
||||
return svgo.optimize(input, {
|
||||
plugins: [
|
||||
'preset-default',
|
||||
'prefixIds',
|
||||
{
|
||||
name: 'sortAttrs',
|
||||
params: {
|
||||
xmlnsOrder: 'alphabetical',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get icon component template
|
||||
*
|
||||
* @param {string} name
|
||||
*/
|
||||
async function getJSXContent(name, svgCode) {
|
||||
let svgrContent = '';
|
||||
try {
|
||||
svgrContent = await svgr.transform(
|
||||
svgCode,
|
||||
{
|
||||
icon: true,
|
||||
typescript: true,
|
||||
},
|
||||
{ componentName: `${name}Icon1` }
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
let matcher = svgrContent.match(/<svg ([^\>]+)>([\s\S]*?)<\/svg>/);
|
||||
return `
|
||||
import { SvgIcon, SvgIconProps } from '@mui/material';
|
||||
export const ${name}Icon = (props: SvgIconProps) => (
|
||||
<SvgIcon ${matcher[1]}>
|
||||
${matcher[2]}
|
||||
</SvgIcon>
|
||||
);
|
||||
`;
|
||||
}
|
||||
|
||||
async function generateImportEntry(iconNodes, folder) {
|
||||
const fileWithImportsPath = path.resolve(folder, 'index.ts');
|
||||
|
||||
const importsContent = iconNodes
|
||||
.map(iconNode => {
|
||||
const iconName = paramCase(iconNode.name);
|
||||
if (!iconName) {
|
||||
return `// Error: ${iconNode.name}`;
|
||||
}
|
||||
|
||||
return `export * from './${iconName}/${iconName}';`;
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
await fs.writeFile(
|
||||
fileWithImportsPath,
|
||||
`export const timestamp = ${Date.now()};\n${importsContent}`,
|
||||
{ encoding: 'utf8' }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} options
|
||||
* @param {array} options.assets
|
||||
* @param {string} options.assets.folder
|
||||
* @param {*} context
|
||||
* @returns
|
||||
*/
|
||||
exports['default'] = async function svgo(options, context) {
|
||||
const libRoot = context.workspace.projects[context.projectName].root;
|
||||
await Promise.allSettled(
|
||||
(options.assets || []).map(async (asset, index) => {
|
||||
await optimizeSvg(path.resolve(libRoot, asset.folder));
|
||||
})
|
||||
);
|
||||
|
||||
return { success: true };
|
||||
};
|
Loading…
Reference in New Issue
Block a user