From fe524dbc78f34c68cb6ceb30342273daabbf7a53 Mon Sep 17 00:00:00 2001 From: Askarbek Zadauly Date: Sun, 2 Apr 2023 18:54:39 +0600 Subject: [PATCH] feat: move kanban blocks (#2022) * chore: add edit / create field test * chore: add delete field test * chore: change log class arguments * chore: delete/create row * chore: set tracing log to debug level * fix: filter notification with id * chore: add get single select type option data * fix: high cpu usage * chore: format code * chore: update tokio version * chore: config tokio runtime subscriber * chore: add profiling feature * chore: setup auto login * chore: fix tauri build * chore: (unstable) using controllers * fix: initially authenticated and serializable fix * fix: ci warning * ci: compile error * fix: new folder trash overflow * fix: min width for nav panel * fix: nav panel and main panel animation on hide menu * fix: highlight active page * fix: post merge fixes * fix: post merge fix * fix: remove warnings * fix: change IDatabaseField fix eslint errors * chore: create cell component for each field type * chore: move cell hook into custom cell component * chore: refactor row hook * chore: add tauri clean * chore: add tauri clean * chore: save offset top of nav items * chore: move constants * fix: nav item popup overflow * fix: page rename position * chore: remove offset top * chore: remove floating menu functions * chore: scroll down to new page * chore: smooth scroll and scroll to new folder * fix: breadcrumbs * chore: back and forward buttons nav scroll fix * chore: get board groups and rows * chore: set log level & remove empty line * fix: create kanban board row * fix: appflowy session name * chore: import beautiful dnd * bug: kanban new row * chore: update refs * fix: dispose group controller * fix: dispose cell controller * chore: move rows in group * chore: move row into other block * fix: groups observer dispose * chore: dnd reordering * chore: fix import references * chore: initial edit board modal * fix: kanban board rendering * chore: add column and edit text cell * chore: column rename * chore: edit row components reorganize * chore: don't show group by field * wip: edit cell type * chore: fade in, out * chore: change field type * chore: update editing cell * chore: fade in change * chore: cell options layout * fix: padding fixes for cell wrapper * fix: cell options positions * chore: cell options write to backend * fix: select options for new row * chore: edit url cell * chore: language button * fix: close popup on lang select * fix: save url cell * chore: date picker * chore: small code cleanups * chore: options in board * chore: move fields dnd --------- Co-authored-by: nathan Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com> Co-authored-by: appflowy --- frontend/appflowy_tauri/package.json | 8 +- .../_shared/EditRow/CellOptions.tsx | 34 +++ .../_shared/EditRow/CellOptionsPopup.tsx | 152 +++++++++++++ .../_shared/EditRow/ChangeFieldTypePopup.tsx | 71 ++++++ .../_shared/EditRow/DatePickerPopup.tsx | 97 ++++++++ .../_shared/EditRow/EditCellDate.tsx | 24 ++ .../_shared/EditRow/EditCellNumber.tsx | 29 +++ .../_shared/EditRow/EditCellText.tsx | 41 ++++ .../_shared/EditRow/EditCellUrl.tsx | 31 +++ .../_shared/EditRow/EditCellWrapper.tsx | 102 +++++++++ .../_shared/EditRow/EditCheckboxCell.tsx | 23 ++ .../_shared/EditRow/EditFieldPopup.tsx | 130 +++++++++++ .../components/_shared/EditRow/EditRow.tsx | 210 ++++++++++++++++++ .../_shared/EditRow/FieldTypeIcon.tsx | 24 ++ .../_shared/EditRow/FieldTypeName.tsx | 18 ++ .../_shared/LanguageSelectPopup.tsx | 5 +- .../_shared/database-hooks/loadField.ts | 2 +- .../_shared/database-hooks/useCell.ts | 39 ++-- .../_shared/database-hooks/useDatabase.ts | 44 +++- .../_shared/database-hooks/useRow.ts | 26 ++- .../components/_shared/svg/ArrowLeftSvg.tsx | 7 + .../components/_shared/svg/ArrowRightSvg.tsx | 7 + .../components/_shared/svg/CheckboxSvg.tsx | 13 ++ .../components/_shared/svg/CheckmarkSvg.tsx | 7 + .../components/_shared/svg/ClockSvg.tsx | 15 ++ .../components/_shared/svg/EditorCheckSvg.tsx | 8 + .../_shared/svg/EditorUncheckSvg.tsx | 7 + .../components/_shared/svg/MoreSvg.tsx | 10 + .../components/_shared/svg/SkipLeftSvg.tsx | 9 + .../components/_shared/svg/SkipRightSvg.tsx | 9 + .../appflowy_app/components/board/Board.tsx | 61 +++-- .../components/board/BoardBlock.tsx | 58 +++-- .../components/board/BoardCard.tsx | 52 +++-- .../components/board/BoardCell.tsx | 7 + .../components/board/BoardOptionsCell.tsx | 10 +- .../components/board/BoardTextCell.tsx | 14 +- .../components/board/BoardUrlCell.tsx | 29 +++ .../components/error/ErrorModal.tsx | 4 +- .../GridTableHeader/GridTableHeader.hooks.tsx | 2 +- .../grid/GridTableHeader/GridTableHeader.tsx | 2 +- .../layout/HeaderPanel/LanguageButton.tsx | 15 ++ .../layout/HeaderPanel/PageOptions.tsx | 5 +- .../NavigationPanel/FolderItem.hooks.ts | 2 +- .../NavigationPanel/NavigationPanel.hooks.ts | 2 +- .../layout/NavigationPanel/PageItem.tsx | 2 +- .../user/application/notifications/parser.ts | 4 +- .../notifications/user_listener.ts | 4 +- .../effects/database/cell/cell_bd_svc.ts | 5 +- .../effects/database/cell/cell_controller.ts | 1 + .../effects/database/cell/cell_observer.ts | 4 +- .../database/cell/controller_builder.ts | 2 +- .../effects/database/cell/data_parser.ts | 6 +- .../effects/database/cell/data_persistence.ts | 6 +- .../database/cell/select_option_bd_svc.ts | 4 +- .../effects/database/database_bd_svc.ts | 40 +++- .../effects/database/database_controller.ts | 33 ++- .../effects/database/field/field_bd_svc.ts | 4 +- .../database/field/field_controller.ts | 6 +- .../effects/database/field/field_observer.ts | 4 +- .../field/type_option/type_option_bd_svc.ts | 4 +- .../field/type_option/type_option_context.ts | 2 +- .../type_option/type_option_controller.ts | 6 +- .../database/group/group_controller.ts | 12 +- .../effects/database/group/group_observer.ts | 4 +- .../database/notifications/observer.ts | 4 +- .../effects/database/notifications/parser.ts | 4 +- .../stores/effects/database/row/row_bd_svc.ts | 4 +- .../stores/effects/database/row/row_cache.ts | 8 +- .../database/view/database_view_cache.ts | 3 +- .../database/view/view_row_observer.ts | 4 +- .../effects/document/document_bd_svc.ts | 6 +- .../stores/effects/folder/app/app_bd_svc.ts | 4 +- .../stores/effects/folder/app/app_observer.ts | 4 +- .../effects/folder/notifications/observer.ts | 4 +- .../effects/folder/notifications/parser.ts | 4 +- .../stores/effects/folder/view/view_bd_svc.ts | 4 +- .../effects/folder/view/view_observer.ts | 5 +- .../folder/workspace/workspace_bd_svc.ts | 4 +- .../folder/workspace/workspace_observer.ts | 4 +- .../stores/effects/user/user_bd_svc.ts | 6 +- .../stores/reducers/current-user/slice.ts | 2 +- .../stores/reducers/database/slice.ts | 4 +- .../reducers/folders/notifications/parser.ts | 4 +- .../stores/reducers/grid/slice.ts | 2 +- .../stores/reducers/pages/slice.ts | 2 +- frontend/appflowy_tauri/src/main.tsx | 1 + .../appflowy_tauri/src/styles/Calendar.css | 141 ++++++++++++ frontend/appflowy_tauri/tailwind.config.cjs | 10 +- 88 files changed, 1660 insertions(+), 196 deletions(-) create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/CellOptions.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/CellOptionsPopup.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/ChangeFieldTypePopup.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/DatePickerPopup.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellDate.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellNumber.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellText.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellUrl.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellWrapper.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCheckboxCell.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditFieldPopup.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditRow.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/FieldTypeIcon.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/FieldTypeName.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/svg/ArrowLeftSvg.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/svg/ArrowRightSvg.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/svg/CheckboxSvg.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/svg/CheckmarkSvg.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/svg/ClockSvg.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/svg/EditorCheckSvg.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/svg/EditorUncheckSvg.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/svg/MoreSvg.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/svg/SkipLeftSvg.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/_shared/svg/SkipRightSvg.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/board/BoardUrlCell.tsx create mode 100644 frontend/appflowy_tauri/src/appflowy_app/components/layout/HeaderPanel/LanguageButton.tsx create mode 100644 frontend/appflowy_tauri/src/styles/Calendar.css diff --git a/frontend/appflowy_tauri/package.json b/frontend/appflowy_tauri/package.json index 9cac4d87c2..6f9ba16df5 100644 --- a/frontend/appflowy_tauri/package.json +++ b/frontend/appflowy_tauri/package.json @@ -23,6 +23,7 @@ "@slate-yjs/core": "^0.3.1", "@tanstack/react-virtual": "3.0.0-beta.54", "@tauri-apps/api": "^1.2.0", + "dayjs": "^1.11.7", "events": "^3.3.0", "google-protobuf": "^3.21.2", "i18next": "^22.4.10", @@ -32,6 +33,8 @@ "nanoid": "^4.0.0", "protoc-gen-ts": "^0.8.5", "react": "^18.2.0", + "react-beautiful-dnd": "^13.1.1", + "react-calendar": "^4.1.0", "react-dom": "^18.2.0", "react-error-boundary": "^3.1.4", "react-i18next": "^12.2.0", @@ -44,8 +47,8 @@ "slate-react": "^0.91.9", "ts-results": "^3.3.0", "utf8": "^3.0.0", - "yjs": "^13.5.51", - "y-indexeddb": "^9.0.9" + "y-indexeddb": "^9.0.9", + "yjs": "^13.5.51" }, "devDependencies": { "@tauri-apps/cli": "^1.2.2", @@ -53,6 +56,7 @@ "@types/is-hotkey": "^0.1.7", "@types/node": "^18.7.10", "@types/react": "^18.0.15", + "@types/react-beautiful-dnd": "^13.1.3", "@types/react-dom": "^18.0.6", "@types/utf8": "^3.0.1", "@types/uuid": "^9.0.1", diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/CellOptions.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/CellOptions.tsx new file mode 100644 index 0000000000..63aeeab62a --- /dev/null +++ b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/CellOptions.tsx @@ -0,0 +1,34 @@ +import { SelectOptionCellDataPB } from '@/services/backend'; +import { getBgColor } from '$app/components/_shared/getColor'; +import { useRef } from 'react'; + +export const CellOptions = ({ + data, + onEditClick, +}: { + data: SelectOptionCellDataPB | undefined; + onEditClick: (left: number, top: number) => void; +}) => { + const ref = useRef(null); + + const onClick = () => { + if (!ref.current) return; + const { left, top } = ref.current.getBoundingClientRect(); + onEditClick(left, top); + }; + + return ( +
onClick()} + className={'flex flex-wrap items-center gap-2 px-4 py-2 text-xs text-black'} + > + {data?.select_options?.map((option, index) => ( +
+ {option?.name || ''} +
+ )) || ''} +   +
+ ); +}; diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/CellOptionsPopup.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/CellOptionsPopup.tsx new file mode 100644 index 0000000000..0a2b1cf09b --- /dev/null +++ b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/CellOptionsPopup.tsx @@ -0,0 +1,152 @@ +import { KeyboardEventHandler, useEffect, useRef, useState } from 'react'; +import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc'; +import { useCell } from '$app/components/_shared/database-hooks/useCell'; +import { CellCache } from '$app/stores/effects/database/cell/cell_cache'; +import { FieldController } from '$app/stores/effects/database/field/field_controller'; +import { SelectOptionCellDataPB, SelectOptionColorPB, SelectOptionPB } from '@/services/backend'; +import { getBgColor } from '$app/components/_shared/getColor'; +import { useTranslation } from 'react-i18next'; +import { Details2Svg } from '$app/components/_shared/svg/Details2Svg'; +import { CheckmarkSvg } from '$app/components/_shared/svg/CheckmarkSvg'; +import { CloseSvg } from '$app/components/_shared/svg/CloseSvg'; +import useOutsideClick from '$app/components/_shared/useOutsideClick'; +import { SelectOptionCellBackendService } from '$app/stores/effects/database/cell/select_option_bd_svc'; +import { useAppSelector } from '$app/stores/store'; +import { ISelectOptionType } from '$app/stores/reducers/database/slice'; + +export const CellOptionsPopup = ({ + top, + left, + cellIdentifier, + cellCache, + fieldController, + onOutsideClick, +}: { + top: number; + left: number; + cellIdentifier: CellIdentifier; + cellCache: CellCache; + fieldController: FieldController; + onOutsideClick: () => void; +}) => { + const ref = useRef(null); + const { t } = useTranslation(''); + const [adjustedTop, setAdjustedTop] = useState(-100); + const [value, setValue] = useState(''); + const { data, cellController } = useCell(cellIdentifier, cellCache, fieldController); + const databaseStore = useAppSelector((state) => state.database); + + useEffect(() => { + if (!ref.current) return; + const { height } = ref.current.getBoundingClientRect(); + if (top + height + 40 > window.innerHeight) { + setAdjustedTop(window.innerHeight - height - 40); + } else { + setAdjustedTop(top); + } + }, [ref, window, top, left]); + + useOutsideClick(ref, async () => { + onOutsideClick(); + }); + + const onKeyDown: KeyboardEventHandler = async (e) => { + if (e.key === 'Enter' && value.length > 0) { + await new SelectOptionCellBackendService(cellIdentifier).createOption({ name: value }); + setValue(''); + } + }; + + const onUnselectOptionClick = async (option: SelectOptionPB) => { + await new SelectOptionCellBackendService(cellIdentifier).unselectOption([option.id]); + setValue(''); + }; + + const onToggleOptionClick = async (option: SelectOptionPB) => { + if ( + (data as SelectOptionCellDataPB | undefined)?.select_options?.find( + (selectedOption) => selectedOption.id === option.id + ) + ) { + await new SelectOptionCellBackendService(cellIdentifier).unselectOption([option.id]); + } else { + await new SelectOptionCellBackendService(cellIdentifier).selectOption([option.id]); + } + setValue(''); + }; + + useEffect(() => { + console.log('loaded data: ', data); + console.log('have stored ', databaseStore.fields[cellIdentifier.fieldId]); + }, [data]); + + return ( +
+
+
+
+ {(data as SelectOptionCellDataPB | undefined)?.select_options?.map((option, index) => ( +
+ {option?.name || ''} + +
+ )) || ''} +
+ setValue(e.target.value)} + placeholder={t('grid.selectOption.searchOption') || ''} + onKeyDown={onKeyDown} + /> +
{value.length}/30
+
+
+
{t('grid.selectOption.panelTitle') || ''}
+
+ {(databaseStore.fields[cellIdentifier.fieldId]?.fieldOptions as ISelectOptionType).selectOptions.map( + (option, index) => ( +
+ onToggleOptionClick( + new SelectOptionPB({ + id: option.selectOptionId, + name: option.title, + color: option.color || SelectOptionColorPB.Purple, + }) + ) + } + className={ + 'flex cursor-pointer items-center justify-between rounded-lg px-2 py-1.5 hover:bg-main-secondary' + } + > +
{option.title}
+
+ {(data as SelectOptionCellDataPB | undefined)?.select_options?.find( + (selectedOption) => selectedOption.id === option.selectOptionId + ) && ( + + )} + +
+
+ ) + )} +
+
+
+ ); +}; diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/ChangeFieldTypePopup.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/ChangeFieldTypePopup.tsx new file mode 100644 index 0000000000..da7e8b0375 --- /dev/null +++ b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/ChangeFieldTypePopup.tsx @@ -0,0 +1,71 @@ +import { FieldType } from '@/services/backend'; +import { FieldTypeIcon } from '$app/components/_shared/EditRow/FieldTypeIcon'; +import { FieldTypeName } from '$app/components/_shared/EditRow/FieldTypeName'; +import { useEffect, useMemo, useRef, useState } from 'react'; +import useOutsideClick from '$app/components/_shared/useOutsideClick'; + +const typesOrder: FieldType[] = [ + FieldType.RichText, + FieldType.Number, + FieldType.DateTime, + FieldType.SingleSelect, + FieldType.MultiSelect, + FieldType.Checkbox, + FieldType.URL, + FieldType.Checklist, +]; + +export const ChangeFieldTypePopup = ({ + top, + right, + onClick, + onOutsideClick, +}: { + top: number; + right: number; + onClick: (newType: FieldType) => void; + onOutsideClick: () => void; +}) => { + const ref = useRef(null); + const [adjustedTop, setAdjustedTop] = useState(-100); + useOutsideClick(ref, async () => { + onOutsideClick(); + }); + + useEffect(() => { + if (!ref.current) return; + const { height } = ref.current.getBoundingClientRect(); + if (top + height > window.innerHeight) { + setAdjustedTop(window.innerHeight - height); + } else { + setAdjustedTop(top); + } + }, [ref, window, top, right]); + + return ( +
+
+ {typesOrder.map((t, i) => ( + + ))} +
+
+ ); +}; diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/DatePickerPopup.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/DatePickerPopup.tsx new file mode 100644 index 0000000000..d7af34ec23 --- /dev/null +++ b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/DatePickerPopup.tsx @@ -0,0 +1,97 @@ +import { useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc'; +import { CellCache } from '$app/stores/effects/database/cell/cell_cache'; +import { FieldController } from '$app/stores/effects/database/field/field_controller'; +import useOutsideClick from '$app/components/_shared/useOutsideClick'; +import Calendar from 'react-calendar'; +import dayjs from 'dayjs'; +import { ClockSvg } from '$app/components/_shared/svg/ClockSvg'; +import { MoreSvg } from '$app/components/_shared/svg/MoreSvg'; +import { EditorUncheckSvg } from '$app/components/_shared/svg/EditorUncheckSvg'; +import { useCell } from '$app/components/_shared/database-hooks/useCell'; + +export const DatePickerPopup = ({ + left, + top, + cellIdentifier, + cellCache, + fieldController, + onOutsideClick, +}: { + left: number; + top: number; + cellIdentifier: CellIdentifier; + cellCache: CellCache; + fieldController: FieldController; + onOutsideClick: () => void; +}) => { + const { data, cellController } = useCell(cellIdentifier, cellCache, fieldController); + const ref = useRef(null); + const [adjustedTop, setAdjustedTop] = useState(-100); + // const [value, setValue] = useState(); + const { t } = useTranslation(''); + const [selectedDate, setSelectedDate] = useState(new Date()); + + useEffect(() => { + if (!ref.current) return; + const { height } = ref.current.getBoundingClientRect(); + if (top + height + 40 > window.innerHeight) { + setAdjustedTop(top - height - 40); + } else { + setAdjustedTop(top); + } + }, [ref, window, top, left]); + + useOutsideClick(ref, async () => { + onOutsideClick(); + }); + + useEffect(() => { + // console.log((data as DateCellDataPB).date); + // setSelectedDate(new Date((data as DateCellDataPB).date)); + }, [data]); + + const onChange = (v: Date | null | (Date | null)[]) => { + if (v instanceof Date) { + console.log(dayjs(v).format('YYYY-MM-DD')); + setSelectedDate(v); + // void cellController?.saveCellData(new DateCellDataPB({ date: dayjs(v).format('YYYY-MM-DD') })); + } + }; + + return ( +
+
+ onChange(d)} value={selectedDate} /> +
+
+
+
+ + + + {t('grid.field.includeTime')} +
+ + + +
+
+
+ + {t('grid.field.dateFormat')} & {t('grid.field.timeFormat')} + + + + +
+
+ ); +}; diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellDate.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellDate.tsx new file mode 100644 index 0000000000..faf24eaf3a --- /dev/null +++ b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellDate.tsx @@ -0,0 +1,24 @@ +import { useRef } from 'react'; +import { DateCellDataPB } from '@/services/backend'; + +export const EditCellDate = ({ + data, + onEditClick, +}: { + data?: DateCellDataPB; + onEditClick: (left: number, top: number) => void; +}) => { + const ref = useRef(null); + + const onClick = () => { + if (!ref.current) return; + const { left, top } = ref.current.getBoundingClientRect(); + onEditClick(left, top); + }; + + return ( +
onClick()} className={'px-4 py-2'}> + {data?.date || <> } +
+ ); +}; diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellNumber.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellNumber.tsx new file mode 100644 index 0000000000..205ddd9257 --- /dev/null +++ b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellNumber.tsx @@ -0,0 +1,29 @@ +import { CellController } from '$app/stores/effects/database/cell/cell_controller'; +import { useEffect, useState } from 'react'; + +export const EditCellNumber = ({ + data, + cellController, +}: { + data: string | undefined; + cellController: CellController; +}) => { + const [value, setValue] = useState(''); + + useEffect(() => { + setValue(data || ''); + }, [data]); + + const save = async () => { + await cellController?.saveCellData(value); + }; + + return ( + setValue(e.target.value)} + onBlur={() => save()} + className={'w-full px-4 py-2'} + > + ); +}; diff --git a/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellText.tsx b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellText.tsx new file mode 100644 index 0000000000..65c09e9880 --- /dev/null +++ b/frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellText.tsx @@ -0,0 +1,41 @@ +import { CellController } from '$app/stores/effects/database/cell/cell_controller'; +import { useEffect, useState, KeyboardEvent, useMemo } from 'react'; + +export const EditCellText = ({ + data, + cellController, +}: { + data: string | undefined; + cellController: CellController; +}) => { + const [value, setValue] = useState(''); + const [contentRows, setContentRows] = useState(1); + + useEffect(() => { + setValue(data || ''); + }, [data]); + + useEffect(() => { + setContentRows(Math.max(1, (value || '').split('\n').length)); + }, [value]); + + const onTextFieldChange = async (v: string) => { + setValue(v); + }; + + const save = async () => { + await cellController?.saveCellData(value); + }; + + return ( +
+