feat: support preview grid/board/calendar block on web (#5401)

This commit is contained in:
Kilu.He 2024-05-23 21:16:52 +08:00 committed by GitHub
parent a0139dd475
commit 857b3aa106
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 243 additions and 105 deletions

View File

@ -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',

View File

@ -4,5 +4,3 @@ export * from './context';
export * from './selector';
export * from './database.type';
export * from './const';
export * from './filter';
export * from './sort';

View File

@ -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) => {

View File

@ -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);
}
})();
}

View File

@ -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);
});
});

View File

@ -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
);
}

View File

@ -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
);
}

View File

@ -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 }) => {

View File

@ -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',

View File

@ -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>
);
});

View File

@ -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} />,

View File

@ -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;
}
}

View File

@ -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) => {

View File

@ -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')}>

View File

@ -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} />
)}

View File

@ -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>
);

View File

@ -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>
);

View File

@ -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={{

View File

@ -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}
/>
);

View File

@ -1,4 +1,3 @@
import { lazy } from 'react';
export const Database = lazy(() => import('./Database'));
export const DatabaseRow = lazy(() => import('./DatabaseRow'));

View File

@ -51,3 +51,5 @@ export const Document = () => {
</>
);
};
export default Document;

View File

@ -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);
});
});

View File

@ -0,0 +1,7 @@
import React from 'react';
function BoardBlock() {
return <div></div>;
}
export default BoardBlock;

View File

@ -0,0 +1,7 @@
import React from 'react';
function CalendarBlock() {
return <div></div>;
}
export default CalendarBlock;

View File

@ -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;

View File

@ -0,0 +1,7 @@
import React from 'react';
function GridBlock() {
return <div></div>;
}
export default GridBlock;

View File

@ -0,0 +1 @@
export * from './DatabaseBlock';

View File

@ -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 {

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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>
);

View File

@ -72,7 +72,7 @@ export default defineConfig({
},
envPrefix: ['AF', 'TAURI_'],
esbuild: {
drop: ['console', 'debugger'],
drop: isDev ? [] : ['console', 'debugger'],
},
build: !!process.env.TAURI_PLATFORM
? {