mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-09-11 19:17:43 +03:00
feat: support preview grid/board/calendar block on web (#5401)
This commit is contained in:
parent
a0139dd475
commit
857b3aa106
@ -27,6 +27,8 @@ export enum BlockType {
|
||||
DividerBlock = 'divider',
|
||||
ImageBlock = 'image',
|
||||
GridBlock = 'grid',
|
||||
BoardBlock = 'board',
|
||||
CalendarBlock = 'calendar',
|
||||
OutlineBlock = 'outline',
|
||||
TableBlock = 'table',
|
||||
TableCell = 'table/cell',
|
||||
@ -111,6 +113,10 @@ export interface TableCellBlockData extends BlockData {
|
||||
width: number;
|
||||
}
|
||||
|
||||
export interface DatabaseNodeData extends BlockData {
|
||||
view_id: ViewId;
|
||||
}
|
||||
|
||||
export enum MentionType {
|
||||
PageRef = 'page',
|
||||
Date = 'date',
|
||||
|
@ -4,5 +4,3 @@ export * from './context';
|
||||
export * from './selector';
|
||||
export * from './database.type';
|
||||
export * from './const';
|
||||
export * from './filter';
|
||||
export * from './sort';
|
||||
|
@ -101,7 +101,7 @@ export function useFieldsSelector(visibilitys: FieldVisibility[] = defaultVisibl
|
||||
visibility: Number(
|
||||
setting?.get(YjsDatabaseKey.visibility) || FieldVisibility.AlwaysShown
|
||||
) as FieldVisibility,
|
||||
wrap: setting?.get(YjsDatabaseKey.wrap),
|
||||
wrap: setting?.get(YjsDatabaseKey.wrap) ?? true,
|
||||
};
|
||||
})
|
||||
.filter((column) => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CollabType, YDoc, YjsEditorKey } from '@/application/collab.type';
|
||||
import { getDBName, openCollabDB } from '@/application/services/js-services/db';
|
||||
import { APIService } from '@/application/services/js-services/wasm';
|
||||
import { applyDocument } from '@/application/ydoc/apply';
|
||||
import { applyYDoc } from '@/application/ydoc/apply';
|
||||
|
||||
export function fetchCollab(workspaceId: string, id: string, type: CollabType) {
|
||||
return APIService.getCollab(workspaceId, id, type);
|
||||
@ -47,7 +47,7 @@ export async function getCollabStorageWithAPICall(workspaceId: string, id: strin
|
||||
const asyncApply = async () => {
|
||||
const res = await fetchCollab(workspaceId, id, type);
|
||||
|
||||
applyDocument(doc, res.state);
|
||||
applyYDoc(doc, res.state);
|
||||
};
|
||||
|
||||
// If the document exists locally, apply the state asynchronously,
|
||||
@ -95,7 +95,7 @@ export async function batchCollabs(
|
||||
|
||||
const { doc } = await getCollabStorage(id, type);
|
||||
|
||||
applyDocument(doc, data);
|
||||
applyYDoc(doc, data);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { YjsEditorKey } from '@/application/collab.type';
|
||||
import { applyDocument } from '@/application/ydoc/apply';
|
||||
import { applyYDoc } from '@/application/ydoc/apply';
|
||||
import * as Y from 'yjs';
|
||||
import * as docJson from '../../../../../cypress/fixtures/simple_doc.json';
|
||||
|
||||
@ -11,7 +11,7 @@ describe('apply document', () => {
|
||||
data.set(YjsEditorKey.document, document);
|
||||
|
||||
const state = new Uint8Array(docJson.data.doc_state);
|
||||
applyDocument(collab, state);
|
||||
applyYDoc(collab, state);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
import { CollabOrigin } from '@/application/collab.type';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
/**
|
||||
* Apply doc state from server to client
|
||||
* Note: origin is always remote
|
||||
* @param doc local Y.Doc
|
||||
* @param state state from server
|
||||
*/
|
||||
export function applyDocument(doc: Y.Doc, state: Uint8Array) {
|
||||
Y.transact(
|
||||
doc,
|
||||
() => {
|
||||
Y.applyUpdate(doc, state);
|
||||
},
|
||||
CollabOrigin.Remote
|
||||
);
|
||||
}
|
@ -1 +1,18 @@
|
||||
export * from 'src/application/ydoc/apply/document';
|
||||
import { CollabOrigin } from '@/application/collab.type';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
/**
|
||||
* Apply doc state from server to client
|
||||
* Note: origin is always remote
|
||||
* @param doc local Y.Doc
|
||||
* @param state state from server
|
||||
*/
|
||||
export function applyYDoc(doc: Y.Doc, state: Uint8Array) {
|
||||
Y.transact(
|
||||
doc,
|
||||
() => {
|
||||
Y.applyUpdate(doc, state);
|
||||
},
|
||||
CollabOrigin.Remote
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { CollabType } from '@/application/collab.type';
|
||||
import { useContext, createContext } from 'react';
|
||||
|
||||
export const IdContext = createContext<IdProviderProps | null>(null);
|
||||
@ -6,7 +5,6 @@ export const IdContext = createContext<IdProviderProps | null>(null);
|
||||
interface IdProviderProps {
|
||||
workspaceId: string;
|
||||
objectId: string;
|
||||
collabType: CollabType;
|
||||
}
|
||||
|
||||
export const IdProvider = ({ children, ...props }: IdProviderProps & { children: React.ReactNode }) => {
|
||||
|
@ -26,7 +26,7 @@ export const RichTooltip = ({ placement = 'top', open, onClose, content, childre
|
||||
anchorEl={childNode}
|
||||
placement={placement}
|
||||
transition
|
||||
style={{ zIndex: 2000 }}
|
||||
style={{ zIndex: 1200 }}
|
||||
modifiers={[
|
||||
{
|
||||
name: 'flip',
|
||||
|
@ -2,7 +2,6 @@ import { YDoc, YjsEditorKey } from '@/application/collab.type';
|
||||
import { useId } from '@/components/_shared/context-provider/IdProvider';
|
||||
import RecordNotFound from '@/components/_shared/not-found/RecordNotFound';
|
||||
import { AFConfigContext } from '@/components/app/AppConfig';
|
||||
import { DatabaseHeader } from '@/components/database/components/header';
|
||||
import DatabaseViews from '@/components/database/DatabaseViews';
|
||||
import { DatabaseContextProvider } from '@/components/database/DatabaseContext';
|
||||
import { Log } from '@/utils/log';
|
||||
@ -71,19 +70,16 @@ export const Database = memo(() => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'relative flex h-full w-full flex-col'}>
|
||||
<DatabaseHeader viewId={objectId} />
|
||||
<div className='appflowy-database relative flex w-full flex-1 select-text flex-col overflow-y-hidden'>
|
||||
<DatabaseContextProvider
|
||||
navigateToRow={navigateToRow}
|
||||
viewId={viewId || objectId}
|
||||
doc={doc}
|
||||
rowDocMap={rows}
|
||||
readOnly={true}
|
||||
>
|
||||
<DatabaseViews onChangeView={handleChangeView} currentViewId={viewId || objectId} />
|
||||
</DatabaseContextProvider>
|
||||
</div>
|
||||
<div className='appflowy-database relative flex w-full flex-1 select-text flex-col overflow-y-hidden'>
|
||||
<DatabaseContextProvider
|
||||
navigateToRow={navigateToRow}
|
||||
viewId={viewId || objectId}
|
||||
doc={doc}
|
||||
rowDocMap={rows}
|
||||
readOnly={true}
|
||||
>
|
||||
<DatabaseViews onChangeView={handleChangeView} currentViewId={viewId || objectId} />
|
||||
</DatabaseContextProvider>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -8,7 +8,7 @@ export function Calendar() {
|
||||
const { dayPropGetter, localizer, formats, events, emptyEvents } = useCalendarSetup();
|
||||
|
||||
return (
|
||||
<div className={'appflowy-calendar h-full max-h-[960px] min-h-[560px] px-16 pt-4 max-md:px-4'}>
|
||||
<div className={'appflowy-calendar h-full max-h-[960px] px-16 pt-4 max-md:px-4'}>
|
||||
<BigCalendar
|
||||
components={{
|
||||
toolbar: (props) => <Toolbar {...props} emptyEvents={emptyEvents} />,
|
||||
|
@ -10,8 +10,9 @@ $today-highlight-bg: transparent;
|
||||
@apply rounded-full w-[20px] h-[20px] my-1.5;
|
||||
}
|
||||
|
||||
.rbc-date-cell {
|
||||
min-width: 100px;
|
||||
|
||||
.rbc-date-cell, .rbc-header {
|
||||
min-width: 120px;
|
||||
max-width: 180px;
|
||||
}
|
||||
|
||||
@ -31,6 +32,7 @@ $today-highlight-bg: transparent;
|
||||
.rbc-month-row {
|
||||
border: 1px solid var(--line-divider);
|
||||
border-top: none;
|
||||
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
@ -57,11 +59,12 @@ $today-highlight-bg: transparent;
|
||||
top: 0;
|
||||
background: var(--bg-body);
|
||||
z-index: 50;
|
||||
@apply border-b border-line-divider;
|
||||
|
||||
.rbc-header {
|
||||
border: none;
|
||||
@apply flex items-end py-2 justify-center font-normal text-text-caption;
|
||||
border-bottom: 1px solid var(--line-divider);
|
||||
@apply flex items-end py-2 justify-center font-normal text-text-caption bg-bg-body;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,30 @@
|
||||
import { useFieldsSelector, useNavigateToRow } from '@/application/database-yjs';
|
||||
import { Property } from '@/components/database/components/property';
|
||||
import { IconButton } from '@mui/material';
|
||||
import { Tooltip } from '@mui/material';
|
||||
import React from 'react';
|
||||
import { ReactComponent as ExpandMoreIcon } from '$icons/16x/full_view.svg';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
function EventPaper({ rowId }: { rowId: string }) {
|
||||
const fields = useFieldsSelector();
|
||||
const navigateToRow = useNavigateToRow();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className={'max-h-[260px] w-[360px] overflow-y-auto'}>
|
||||
<div className={'flex h-fit w-full flex-col items-center justify-center py-2 px-3'}>
|
||||
<div className={'flex w-full items-center justify-end'}>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
navigateToRow?.(rowId);
|
||||
}}
|
||||
size={'small'}
|
||||
>
|
||||
<ExpandMoreIcon />
|
||||
</IconButton>
|
||||
<Tooltip placement={'bottom'} title={t('tooltip.openAsPage')}>
|
||||
<button
|
||||
color={'primary'}
|
||||
className={'rounded bg-bg-body p-1 hover:bg-fill-list-hover'}
|
||||
onClick={() => {
|
||||
navigateToRow?.(rowId);
|
||||
}}
|
||||
>
|
||||
<ExpandMoreIcon />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className={'event-properties flex w-full flex-1 flex-col gap-4 overflow-y-auto py-2'}>
|
||||
{fields.map((field) => {
|
||||
|
@ -3,26 +3,45 @@ import { useNavigateToRow, useRowMetaSelector } from '@/application/database-yjs
|
||||
import { TextCell as CellType, CellProps } from '@/components/database/components/cell/cell.type';
|
||||
import { TextCell } from '@/components/database/components/cell/text';
|
||||
import { Tooltip } from '@mui/material';
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export function PrimaryCell(props: CellProps<CellType>) {
|
||||
const navigateToRow = useNavigateToRow();
|
||||
const { rowId } = props;
|
||||
// const icon = null;
|
||||
const icon = useRowMetaSelector(rowId)?.icon;
|
||||
|
||||
const [hover, setHover] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
const table = document.querySelector('.grid-table');
|
||||
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
|
||||
const onMouseMove = (e: Event) => {
|
||||
const target = e.target as HTMLElement;
|
||||
|
||||
if (target.closest('.grid-row-cell')?.getAttribute('data-row-id') === rowId) {
|
||||
setHover(true);
|
||||
} else {
|
||||
setHover(false);
|
||||
}
|
||||
};
|
||||
|
||||
table.addEventListener('mousemove', onMouseMove);
|
||||
return () => {
|
||||
table.removeEventListener('mousemove', onMouseMove);
|
||||
};
|
||||
}, [rowId]);
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={() => setHover(true)}
|
||||
onMouseLeave={() => setHover(false)}
|
||||
className={'primary-cell relative flex w-full items-center gap-2'}
|
||||
>
|
||||
<div className={'primary-cell relative flex min-h-full w-full items-center gap-2'}>
|
||||
{icon && <div className={'h-4 w-4'}>{icon}</div>}
|
||||
<TextCell {...props} />
|
||||
<div className={'flex-1 overflow-x-hidden'}>
|
||||
<TextCell {...props} />
|
||||
</div>
|
||||
|
||||
{hover && (
|
||||
<Tooltip placement={'bottom'} title={t('tooltip.openAsPage')}>
|
||||
|
@ -35,12 +35,12 @@ function RelationItems({ style, cell, fieldId }: { cell: RelationCell; fieldId:
|
||||
}, [workspaceId, databaseId, databaseService, rowIds]);
|
||||
|
||||
return (
|
||||
<div style={style} className={'flex items-center gap-2'}>
|
||||
<div style={style} className={'relation-cell flex w-full items-center gap-2'}>
|
||||
{rowIds.map((rowId) => {
|
||||
const rowDoc = rows?.get(rowId);
|
||||
|
||||
return (
|
||||
<div key={rowId} className={'cursor-pointer underline'}>
|
||||
<div key={rowId} className={'w-full cursor-pointer underline'}>
|
||||
{rowDoc && databasePrimaryFieldId && (
|
||||
<RelationPrimaryValue rowDoc={rowDoc} fieldId={databasePrimaryFieldId} />
|
||||
)}
|
||||
|
@ -31,7 +31,10 @@ export function SelectOptionCell({ cell, fieldId, style, placeholder }: CellProp
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div style={style} className={'flex h-full w-full cursor-pointer items-center gap-1 overflow-x-hidden'}>
|
||||
<div
|
||||
style={style}
|
||||
className={'select-option-cell flex h-full w-full cursor-pointer items-center gap-1 overflow-x-hidden'}
|
||||
>
|
||||
{renderSelectedOptions(selectOptionIds)}
|
||||
</div>
|
||||
);
|
||||
|
@ -7,7 +7,7 @@ export function TextCell({ cell, style }: CellProps<TextCellType>) {
|
||||
|
||||
if (!cell?.data) return null;
|
||||
return (
|
||||
<div style={style} className={`cursor-text leading-[1.2] ${readOnly ? 'select-text' : ''}`}>
|
||||
<div style={style} className={`text-cell w-full cursor-text leading-[1.2] ${readOnly ? 'select-text' : ''}`}>
|
||||
{cell?.data}
|
||||
</div>
|
||||
);
|
||||
|
@ -94,10 +94,10 @@ export const GridTable = ({ scrollLeft, columnWidth, columns, onScrollLeft }: Gr
|
||||
const row = data.rows[rowIndex];
|
||||
const column = data.columns[columnIndex] as RenderColumn;
|
||||
|
||||
const classList = ['flex', 'items-center', 'overflow-hidden'];
|
||||
const classList = ['flex', 'items-center', 'overflow-hidden', 'grid-row-cell'];
|
||||
|
||||
if (column.wrap) {
|
||||
classList.push('whitespace-pre-wrap', 'break-words');
|
||||
classList.push('wrap-cell');
|
||||
} else {
|
||||
classList.push('whitespace-nowrap');
|
||||
}
|
||||
@ -113,6 +113,7 @@ export const GridTable = ({ scrollLeft, columnWidth, columns, onScrollLeft }: Gr
|
||||
if (row.type === RenderRowType.Row) {
|
||||
return (
|
||||
<div
|
||||
data-row-id={row.rowId}
|
||||
className={classList.join(' ')}
|
||||
style={{ ...style, borderLeftWidth: columnIndex === 1 || column.type === GridColumnType.Action ? 0 : 1 }}
|
||||
>
|
||||
@ -153,6 +154,7 @@ export const GridTable = ({ scrollLeft, columnWidth, columns, onScrollLeft }: Gr
|
||||
columnCount={columns.length}
|
||||
columnWidth={(index) => columnWidth(index, width)}
|
||||
rowHeight={rowHeight}
|
||||
className={'grid-table'}
|
||||
overscanRowCount={5}
|
||||
overscanColumnCount={5}
|
||||
style={{
|
||||
|
@ -83,7 +83,7 @@ export const DatabaseTabs = forwardRef<HTMLDivElement, DatabaseTabBarProps>(
|
||||
icon={<Icon className={'h-4 w-4'} />}
|
||||
iconPosition='start'
|
||||
color='inherit'
|
||||
label={name || t('grid.title.placeholder')}
|
||||
label={<span className={'max-w-[120px] truncate'}>{name || t('grid.title.placeholder')}</span>}
|
||||
value={viewId}
|
||||
/>
|
||||
);
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const Database = lazy(() => import('./Database'));
|
||||
export const DatabaseRow = lazy(() => import('./DatabaseRow'));
|
||||
|
@ -51,3 +51,5 @@ export const Document = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Document;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { YDoc } from '@/application/collab.type';
|
||||
import { DocumentTest } from '@/../cypress/support/document';
|
||||
import { applyDocument } from '@/application/ydoc/apply';
|
||||
import { applyYDoc } from '@/application/ydoc/apply';
|
||||
import React from 'react';
|
||||
import * as Y from 'yjs';
|
||||
import { Editor } from './Editor';
|
||||
@ -20,7 +20,7 @@ describe('<Editor />', () => {
|
||||
const doc = new Y.Doc();
|
||||
const state = new Uint8Array(docJson.data.doc_state);
|
||||
|
||||
applyDocument(doc, state);
|
||||
applyYDoc(doc, state);
|
||||
renderEditor(doc);
|
||||
});
|
||||
});
|
||||
|
@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
function BoardBlock() {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
export default BoardBlock;
|
@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
function CalendarBlock() {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
export default CalendarBlock;
|
@ -0,0 +1,60 @@
|
||||
import { IdProvider, useId } from '@/components/_shared/context-provider/IdProvider';
|
||||
import { Database } from '@/components/database';
|
||||
import { DatabaseNode, EditorElementProps } from '@/components/editor/editor.type';
|
||||
import React, { forwardRef, memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { BlockType } from '@/application/collab.type';
|
||||
|
||||
export const DatabaseBlock = memo(
|
||||
forwardRef<HTMLDivElement, EditorElementProps<DatabaseNode>>(({ node, children, ...attributes }, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const viewId = node.data.view_id;
|
||||
const workspaceId = useId()?.workspaceId;
|
||||
const type = node.type;
|
||||
|
||||
const style = useMemo(() => {
|
||||
const style = {};
|
||||
|
||||
switch (type) {
|
||||
case BlockType.GridBlock:
|
||||
Object.assign(style, {
|
||||
height: 360,
|
||||
});
|
||||
break;
|
||||
case BlockType.CalendarBlock:
|
||||
case BlockType.BoardBlock:
|
||||
Object.assign(style, {
|
||||
height: 560,
|
||||
});
|
||||
}
|
||||
|
||||
return style;
|
||||
}, [type]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div {...attributes} className={`relative w-full cursor-pointer py-2`}>
|
||||
<div ref={ref} className={'absolute left-0 top-0 h-full w-full caret-transparent'}>
|
||||
{children}
|
||||
</div>
|
||||
<div contentEditable={false} style={style} className={`container-bg flex w-full flex-col px-3`}>
|
||||
{viewId ? (
|
||||
<IdProvider workspaceId={workspaceId} objectId={viewId}>
|
||||
<Database />
|
||||
</IdProvider>
|
||||
) : (
|
||||
<div
|
||||
className={'mt-[10%] flex h-full w-full flex-col items-center gap-2 px-16 text-text-caption max-md:px-4'}
|
||||
>
|
||||
<div className={'text-sm font-medium'}>{t('document.plugins.database.noDataSource')}</div>
|
||||
<div className={'text-xs'}>{t('grid.relation.noDatabaseSelected')}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
export default DatabaseBlock;
|
@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
function GridBlock() {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
export default GridBlock;
|
@ -0,0 +1 @@
|
||||
export * from './DatabaseBlock';
|
@ -1,12 +1,12 @@
|
||||
import { BlockType } from '@/application/collab.type';
|
||||
import { BulletedListIcon } from '@/components/editor/components/blocks/bulleted_list';
|
||||
import { NumberListIcon } from '@/components/editor/components/blocks/numbered_list';
|
||||
import ToggleIcon from '@/components/editor/components/blocks/toggle_list/ToggleIcon';
|
||||
import { BulletedListIcon } from '@/components/editor/components/blocks/bulleted-list';
|
||||
import { NumberListIcon } from '@/components/editor/components/blocks/numbered-list';
|
||||
import ToggleIcon from '@/components/editor/components/blocks/toggle-list/ToggleIcon';
|
||||
import { TextNode } from '@/components/editor/editor.type';
|
||||
import React, { FC, useCallback, useMemo } from 'react';
|
||||
import { ReactEditor, useSlate } from 'slate-react';
|
||||
import { Editor, Element } from 'slate';
|
||||
import CheckboxIcon from '../todo_list/CheckboxIcon';
|
||||
import CheckboxIcon from '@/components/editor/components/blocks/todo-list/CheckboxIcon';
|
||||
|
||||
export function useStartIcon(node: TextNode) {
|
||||
const editor = useSlate();
|
||||
@ -37,7 +37,7 @@ export function useStartIcon(node: TextNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <Component className={`text-block-icon relative`} block={block} />;
|
||||
return <Component className={`text-block-icon relative h-[24px] w-[24px]`} block={block} />;
|
||||
}, [Component, block]);
|
||||
|
||||
return {
|
||||
|
@ -1,20 +1,20 @@
|
||||
import { BlockData, BlockType, InlineBlockType, YjsEditorKey } from '@/application/collab.type';
|
||||
import { BulletedList } from '@/components/editor/components/blocks/bulleted_list';
|
||||
import { BulletedList } from '@/components/editor/components/blocks/bulleted-list';
|
||||
import { Callout } from '@/components/editor/components/blocks/callout';
|
||||
import { CodeBlock } from '@/components/editor/components/blocks/code';
|
||||
import { DividerNode } from '@/components/editor/components/blocks/divider';
|
||||
import { Heading } from '@/components/editor/components/blocks/heading';
|
||||
import { ImageBlock } from '@/components/editor/components/blocks/image';
|
||||
import { MathEquation } from '@/components/editor/components/blocks/math_equation';
|
||||
import { NumberedList } from '@/components/editor/components/blocks/numbered_list';
|
||||
import { MathEquation } from '@/components/editor/components/blocks/math-equation';
|
||||
import { NumberedList } from '@/components/editor/components/blocks/numbered-list';
|
||||
import { Outline } from '@/components/editor/components/blocks/outline';
|
||||
import { Page } from '@/components/editor/components/blocks/page';
|
||||
import { Paragraph } from '@/components/editor/components/blocks/paragraph';
|
||||
import { Quote } from '@/components/editor/components/blocks/quote';
|
||||
import { TableBlock, TableCellBlock } from '@/components/editor/components/blocks/table';
|
||||
import { Text } from '@/components/editor/components/blocks/text';
|
||||
import { TodoList } from '@/components/editor/components/blocks/todo_list';
|
||||
import { ToggleList } from '@/components/editor/components/blocks/toggle_list';
|
||||
import { TodoList } from 'src/components/editor/components/blocks/todo-list';
|
||||
import { ToggleList } from 'src/components/editor/components/blocks/toggle-list';
|
||||
import { UnSupportedBlock } from '@/components/editor/components/element/UnSupportedBlock';
|
||||
import { Formula } from '@/components/editor/components/leaf/formula';
|
||||
import { Mention } from '@/components/editor/components/leaf/mention';
|
||||
@ -22,6 +22,7 @@ import { EditorElementProps, TextNode } from '@/components/editor/editor.type';
|
||||
import { renderColor } from '@/utils/color';
|
||||
import React, { FC, useMemo } from 'react';
|
||||
import { RenderElementProps } from 'slate-react';
|
||||
import { DatabaseBlock } from 'src/components/editor/components/blocks/database';
|
||||
|
||||
export const Element = ({
|
||||
element: node,
|
||||
@ -64,6 +65,10 @@ export const Element = ({
|
||||
return TableBlock;
|
||||
case BlockType.TableCell:
|
||||
return TableCellBlock;
|
||||
case BlockType.GridBlock:
|
||||
case BlockType.BoardBlock:
|
||||
case BlockType.CalendarBlock:
|
||||
return DatabaseBlock;
|
||||
default:
|
||||
return UnSupportedBlock;
|
||||
}
|
||||
|
@ -10,9 +10,7 @@ export function Leaf({ attributes, children, leaf }: RenderLeafProps) {
|
||||
const classList = [leaf.prism_token, leaf.prism_token && 'token', leaf.class_name].filter(Boolean);
|
||||
|
||||
if (leaf.code) {
|
||||
newChildren = (
|
||||
<span className={'bg-fill-list-active bg-opacity-50 text-xs font-medium text-[#EB5757]'}>{newChildren}</span>
|
||||
);
|
||||
newChildren = <span className={'bg-line-divider font-medium text-[#EB5757]'}>{newChildren}</span>;
|
||||
}
|
||||
|
||||
if (leaf.underline) {
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
TableCellBlockData,
|
||||
BlockId,
|
||||
BlockData,
|
||||
DatabaseNodeData,
|
||||
} from '@/application/collab.type';
|
||||
import { HTMLAttributes } from 'react';
|
||||
import { Element } from 'slate';
|
||||
@ -120,6 +121,12 @@ export interface TableCellNode extends BlockNode {
|
||||
data: TableCellBlockData;
|
||||
}
|
||||
|
||||
export interface DatabaseNode extends BlockNode {
|
||||
type: BlockType.GridBlock | BlockType.BoardBlock | BlockType.CalendarBlock;
|
||||
blockId: string;
|
||||
data: DatabaseNodeData;
|
||||
}
|
||||
|
||||
export interface EditorElementProps<T = Element> extends HTMLAttributes<HTMLDivElement> {
|
||||
node: T;
|
||||
}
|
||||
|
@ -91,8 +91,22 @@
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
boxShadow: var(--shadow);
|
||||
backgroundColor: var(--bg-body);
|
||||
box-shadow: var(--shadow);
|
||||
background-color: var(--bg-body);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.grid-row-cell.wrap-cell {
|
||||
.text-cell {
|
||||
@apply py-2 break-words whitespace-pre-wrap;
|
||||
}
|
||||
|
||||
.relation-cell {
|
||||
@apply py-2 break-words whitespace-pre-wrap flex-wrap;
|
||||
}
|
||||
|
||||
.select-option-cell {
|
||||
@apply flex-wrap py-2;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
import { Database, DatabaseRow } from '@/components/database';
|
||||
import { useId } from '@/components/_shared/context-provider/IdProvider';
|
||||
import { DatabaseHeader } from '@/components/database/components/header';
|
||||
import React from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import DatabaseRow from '@/components/database/DatabaseRow';
|
||||
import Database from '@/components/database/Database';
|
||||
|
||||
function DatabasePage() {
|
||||
const objectId = useId()?.objectId;
|
||||
const [search] = useSearchParams();
|
||||
const rowId = search.get('r');
|
||||
|
||||
@ -10,7 +14,12 @@ function DatabasePage() {
|
||||
return <DatabaseRow rowId={rowId} />;
|
||||
}
|
||||
|
||||
return <Database />;
|
||||
return (
|
||||
<div className={'relative flex h-full w-full flex-col'}>
|
||||
<DatabaseHeader viewId={objectId} />
|
||||
<Database />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DatabasePage;
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { CollabType } from '@/application/collab.type';
|
||||
import { IdProvider } from '@/components/_shared/context-provider/IdProvider';
|
||||
import DatabasePage from '@/pages/DatabasePage';
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { lazy, useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import DocumentPage from '@/pages/DocumentPage';
|
||||
|
||||
const DatabasePage = lazy(() => import('./DatabasePage'));
|
||||
|
||||
enum URL_COLLAB_TYPE {
|
||||
DOCUMENT = 'document',
|
||||
GRID = 'grid',
|
||||
@ -12,13 +12,6 @@ enum URL_COLLAB_TYPE {
|
||||
CALENDAR = 'calendar',
|
||||
}
|
||||
|
||||
const collabTypeMap: Record<string, CollabType> = {
|
||||
[URL_COLLAB_TYPE.DOCUMENT]: CollabType.Document,
|
||||
[URL_COLLAB_TYPE.GRID]: CollabType.WorkspaceDatabase,
|
||||
[URL_COLLAB_TYPE.BOARD]: CollabType.WorkspaceDatabase,
|
||||
[URL_COLLAB_TYPE.CALENDAR]: CollabType.WorkspaceDatabase,
|
||||
};
|
||||
|
||||
function ProductPage() {
|
||||
const { workspaceId, type, objectId } = useParams();
|
||||
const PageComponent = useMemo(() => {
|
||||
@ -38,7 +31,7 @@ function ProductPage() {
|
||||
if (!workspaceId || !type || !objectId) return null;
|
||||
|
||||
return (
|
||||
<IdProvider workspaceId={workspaceId} objectId={objectId} collabType={collabTypeMap[type]}>
|
||||
<IdProvider workspaceId={workspaceId} objectId={objectId}>
|
||||
{PageComponent && <PageComponent />}
|
||||
</IdProvider>
|
||||
);
|
||||
|
@ -72,7 +72,7 @@ export default defineConfig({
|
||||
},
|
||||
envPrefix: ['AF', 'TAURI_'],
|
||||
esbuild: {
|
||||
drop: ['console', 'debugger'],
|
||||
drop: isDev ? [] : ['console', 'debugger'],
|
||||
},
|
||||
build: !!process.env.TAURI_PLATFORM
|
||||
? {
|
||||
|
Loading…
Reference in New Issue
Block a user