Browse Source

chore: edit cell options wip

ascarbek 2 years ago
parent
commit
6bbf6873d6

+ 18 - 3
frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/CellOptionsPopup.tsx

@@ -1,4 +1,4 @@
-import { KeyboardEventHandler, useEffect, useRef, useState } from 'react';
+import { KeyboardEventHandler, MouseEventHandler, useEffect, useRef, useState } from 'react';
 import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc';
 import { CellIdentifier } from '$app/stores/effects/database/cell/cell_bd_svc';
 import { useCell } from '$app/components/_shared/database-hooks/useCell';
 import { useCell } from '$app/components/_shared/database-hooks/useCell';
 import { CellCache } from '$app/stores/effects/database/cell/cell_cache';
 import { CellCache } from '$app/stores/effects/database/cell/cell_cache';
@@ -21,6 +21,7 @@ export const CellOptionsPopup = ({
   cellCache,
   cellCache,
   fieldController,
   fieldController,
   onOutsideClick,
   onOutsideClick,
+  openOptionDetail,
 }: {
 }: {
   top: number;
   top: number;
   left: number;
   left: number;
@@ -28,6 +29,7 @@ export const CellOptionsPopup = ({
   cellCache: CellCache;
   cellCache: CellCache;
   fieldController: FieldController;
   fieldController: FieldController;
   onOutsideClick: () => void;
   onOutsideClick: () => void;
+  openOptionDetail: (_left: number, _top: number) => void;
 }) => {
 }) => {
   const ref = useRef<HTMLDivElement>(null);
   const ref = useRef<HTMLDivElement>(null);
   const inputRef = useRef<HTMLInputElement>(null);
   const inputRef = useRef<HTMLInputElement>(null);
@@ -88,6 +90,19 @@ export const CellOptionsPopup = ({
     }
     }
   };
   };
 
 
+  const onOptionDetailClick: MouseEventHandler = (e) => {
+    e.stopPropagation();
+    let target = e.target as HTMLElement;
+
+    while (!(target instanceof HTMLButtonElement)) {
+      if (target.parentElement === null) return;
+      target = target.parentElement;
+    }
+
+    const { right: _left, top: _top } = target.getBoundingClientRect();
+    openOptionDetail(_left, _top);
+  };
+
   return (
   return (
     <div
     <div
       ref={ref}
       ref={ref}
@@ -120,7 +135,7 @@ export const CellOptionsPopup = ({
           <div className={'font-mono text-shade-3'}>{value.length}/30</div>
           <div className={'font-mono text-shade-3'}>{value.length}/30</div>
         </div>
         </div>
         <div className={'-mx-4 h-[1px] bg-shade-6'}></div>
         <div className={'-mx-4 h-[1px] bg-shade-6'}></div>
-        <div className={'font-semibold text-shade-3'}>{t('grid.selectOption.panelTitle') || ''}</div>
+        <div className={'font-medium text-shade-3'}>{t('grid.selectOption.panelTitle') || ''}</div>
         <div className={'flex flex-col gap-1'}>
         <div className={'flex flex-col gap-1'}>
           {(databaseStore.fields[cellIdentifier.fieldId]?.fieldOptions as ISelectOptionType).selectOptions.map(
           {(databaseStore.fields[cellIdentifier.fieldId]?.fieldOptions as ISelectOptionType).selectOptions.map(
             (option, index) => (
             (option, index) => (
@@ -148,7 +163,7 @@ export const CellOptionsPopup = ({
                       <CheckmarkSvg></CheckmarkSvg>
                       <CheckmarkSvg></CheckmarkSvg>
                     </button>
                     </button>
                   )}
                   )}
-                  <button className={'h-6 w-6 p-1'}>
+                  <button onClick={onOptionDetailClick} className={'h-6 w-6 p-1'}>
                     <Details2Svg></Details2Svg>
                     <Details2Svg></Details2Svg>
                   </button>
                   </button>
                 </div>
                 </div>

+ 185 - 0
frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditCellOptionPopup.tsx

@@ -0,0 +1,185 @@
+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 { KeyboardEventHandler, useEffect, useRef, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { SelectOptionCellDataPB, SelectOptionColorPB } from '@/services/backend';
+import { getBgColor } from '$app/components/_shared/getColor';
+import { CloseSvg } from '$app/components/_shared/svg/CloseSvg';
+import { SelectOptionCellBackendService } from '$app/stores/effects/database/cell/select_option_bd_svc';
+import useOutsideClick from '$app/components/_shared/useOutsideClick';
+import { TrashSvg } from '$app/components/_shared/svg/TrashSvg';
+import { CheckmarkSvg } from '$app/components/_shared/svg/CheckmarkSvg';
+
+export const EditCellOptionPopup = ({
+  left,
+  top,
+  cellIdentifier,
+  cellCache,
+  fieldController,
+  onOutsideClick,
+}: {
+  left: number;
+  top: number;
+  cellIdentifier: CellIdentifier;
+  cellCache: CellCache;
+  fieldController: FieldController;
+  onOutsideClick: () => void;
+}) => {
+  const ref = useRef<HTMLDivElement>(null);
+  const inputRef = useRef<HTMLInputElement>(null);
+  const { t } = useTranslation('');
+  const [adjustedTop, setAdjustedTop] = useState(-100);
+  const [value, setValue] = useState('');
+
+  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, left]);
+
+  const onKeyDown: KeyboardEventHandler = async (e) => {
+    if (e.key === 'Enter' && value.length > 0) {
+      await new SelectOptionCellBackendService(cellIdentifier).createOption({ name: value });
+      setValue('');
+    }
+  };
+
+  const onKeyDownWrapper: KeyboardEventHandler = (e) => {
+    if (e.key === 'Escape') {
+      onOutsideClick();
+    }
+  };
+
+  const onDeleteOptionClick = () => {
+    console.log('delete option');
+  };
+
+  return (
+    <div
+      ref={ref}
+      onKeyDown={onKeyDownWrapper}
+      className={`fixed z-10 rounded-lg bg-white px-2 py-2 text-xs shadow-md transition-opacity duration-300 ${
+        adjustedTop === -100 ? 'opacity-0' : 'opacity-100'
+      }`}
+      style={{ top: `${adjustedTop}px`, left: `${left}px` }}
+    >
+      <div className={'flex flex-col gap-2 p-2'}>
+        <div className={'border-shades-3 flex flex-1 items-center gap-2 rounded border bg-main-selector px-2 '}>
+          <input
+            ref={inputRef}
+            className={'py-2'}
+            value={value}
+            onChange={(e) => setValue(e.target.value)}
+            onKeyDown={onKeyDown}
+          />
+          <div className={'font-mono text-shade-3'}>{value.length}/30</div>
+        </div>
+        <button
+          onClick={() => onDeleteOptionClick()}
+          className={
+            'flex cursor-pointer items-center gap-2 rounded-lg px-2 py-2 text-main-alert hover:bg-main-secondary'
+          }
+        >
+          <i className={'h-5 w-5'}>
+            <TrashSvg></TrashSvg>
+          </i>
+          <span>{t('grid.selectOption.deleteTag')}</span>
+        </button>
+        <div className={'-mx-4 h-[1px] bg-shade-6'}></div>
+        <div className={'my-2 font-medium text-shade-3'}>{t('grid.selectOption.colorPanelTitle')}</div>
+        <div className={'flex flex-col'}>
+          <div className={'flex cursor-pointer items-center justify-between rounded-lg p-2 hover:bg-main-secondary'}>
+            <div className={'flex items-center gap-2'}>
+              <div className={`h-4 w-4 rounded-full ${getBgColor(SelectOptionColorPB.Purple)}`}></div>
+              <span>{t('grid.selectOption.purpleColor')}</span>
+            </div>
+            <i className={'block h-3 w-3'}>
+              <CheckmarkSvg></CheckmarkSvg>
+            </i>
+          </div>
+          <div className={'flex cursor-pointer items-center justify-between rounded-lg p-2 hover:bg-main-secondary'}>
+            <div className={'flex items-center gap-2'}>
+              <div className={`h-4 w-4 rounded-full ${getBgColor(SelectOptionColorPB.Pink)}`}></div>
+              <span>{t('grid.selectOption.pinkColor')}</span>
+            </div>
+            <i className={'block h-3 w-3'}>
+              <CheckmarkSvg></CheckmarkSvg>
+            </i>
+          </div>
+          <div className={'flex cursor-pointer items-center justify-between rounded-lg p-2 hover:bg-main-secondary'}>
+            <div className={'flex items-center gap-2'}>
+              <div className={`h-4 w-4 rounded-full ${getBgColor(SelectOptionColorPB.LightPink)}`}></div>
+              <span>{t('grid.selectOption.lightPinkColor')}</span>
+            </div>
+            <i className={'block h-3 w-3'}>
+              <CheckmarkSvg></CheckmarkSvg>
+            </i>
+          </div>
+          <div className={'flex cursor-pointer items-center justify-between rounded-lg p-2 hover:bg-main-secondary'}>
+            <div className={'flex items-center gap-2'}>
+              <div className={`h-4 w-4 rounded-full ${getBgColor(SelectOptionColorPB.Orange)}`}></div>
+              <span>{t('grid.selectOption.orangeColor')}</span>
+            </div>
+            <i className={'block h-3 w-3'}>
+              <CheckmarkSvg></CheckmarkSvg>
+            </i>
+          </div>
+          <div className={'flex cursor-pointer items-center justify-between rounded-lg p-2 hover:bg-main-secondary'}>
+            <div className={'flex items-center gap-2'}>
+              <div className={`h-4 w-4 rounded-full ${getBgColor(SelectOptionColorPB.Yellow)}`}></div>
+              <span>{t('grid.selectOption.yellowColor')}</span>
+            </div>
+            <i className={'block h-3 w-3'}>
+              <CheckmarkSvg></CheckmarkSvg>
+            </i>
+          </div>
+          <div className={'flex cursor-pointer items-center justify-between rounded-lg p-2 hover:bg-main-secondary'}>
+            <div className={'flex items-center gap-2'}>
+              <div className={`h-4 w-4 rounded-full ${getBgColor(SelectOptionColorPB.Lime)}`}></div>
+              <span>{t('grid.selectOption.limeColor')}</span>
+            </div>
+            <i className={'block h-3 w-3'}>
+              <CheckmarkSvg></CheckmarkSvg>
+            </i>
+          </div>
+          <div className={'flex cursor-pointer items-center justify-between rounded-lg p-2 hover:bg-main-secondary'}>
+            <div className={'flex items-center gap-2'}>
+              <div className={`h-4 w-4 rounded-full ${getBgColor(SelectOptionColorPB.Green)}`}></div>
+              <span>{t('grid.selectOption.greenColor')}</span>
+            </div>
+            <i className={'block h-3 w-3'}>
+              <CheckmarkSvg></CheckmarkSvg>
+            </i>
+          </div>
+          <div className={'flex cursor-pointer items-center justify-between rounded-lg p-2 hover:bg-main-secondary'}>
+            <div className={'flex items-center gap-2'}>
+              <div className={`h-4 w-4 rounded-full ${getBgColor(SelectOptionColorPB.Aqua)}`}></div>
+              <span>{t('grid.selectOption.aquaColor')}</span>
+            </div>
+            <i className={'block h-3 w-3'}>
+              <CheckmarkSvg></CheckmarkSvg>
+            </i>
+          </div>
+          <div className={'flex cursor-pointer items-center justify-between rounded-lg p-2 hover:bg-main-secondary'}>
+            <div className={'flex items-center gap-2'}>
+              <div className={`h-4 w-4 rounded-full ${getBgColor(SelectOptionColorPB.Blue)}`}></div>
+              <span>{t('grid.selectOption.blueColor')}</span>
+            </div>
+            <i className={'block h-3 w-3'}>
+              <CheckmarkSvg></CheckmarkSvg>
+            </i>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};

+ 24 - 0
frontend/appflowy_tauri/src/appflowy_app/components/_shared/EditRow/EditRow.tsx

@@ -15,6 +15,7 @@ import { FieldType } from '@/services/backend';
 import { CellOptionsPopup } from '$app/components/_shared/EditRow/CellOptionsPopup';
 import { CellOptionsPopup } from '$app/components/_shared/EditRow/CellOptionsPopup';
 import { DatePickerPopup } from '$app/components/_shared/EditRow/DatePickerPopup';
 import { DatePickerPopup } from '$app/components/_shared/EditRow/DatePickerPopup';
 import { DragDropContext, Droppable, OnDragEndResponder } from 'react-beautiful-dnd';
 import { DragDropContext, Droppable, OnDragEndResponder } from 'react-beautiful-dnd';
+import { EditCellOptionPopup } from '$app/components/_shared/EditRow/EditCellOptionPopup';
 
 
 export const EditRow = ({
 export const EditRow = ({
   onClose,
   onClose,
@@ -48,6 +49,10 @@ export const EditRow = ({
   const [datePickerTop, setDatePickerTop] = useState(0);
   const [datePickerTop, setDatePickerTop] = useState(0);
   const [datePickerLeft, setDatePickerLeft] = useState(0);
   const [datePickerLeft, setDatePickerLeft] = useState(0);
 
 
+  const [showEditCellOption, setShowEditCellOption] = useState(false);
+  const [editCellOptionTop, setEditCellOptionTop] = useState(0);
+  const [editCellOptionLeft, setEditCellOptionLeft] = useState(0);
+
   useEffect(() => {
   useEffect(() => {
     setUnveil(true);
     setUnveil(true);
   }, []);
   }, []);
@@ -106,6 +111,12 @@ export const EditRow = ({
     setShowDatePicker(true);
     setShowDatePicker(true);
   };
   };
 
 
+  const onOpenOptionDetailClick = (_left: number, _top: number) => {
+    setShowEditCellOption(true);
+    setEditCellOptionLeft(_left);
+    setEditCellOptionTop(_top);
+  };
+
   const onDragEnd: OnDragEndResponder = (result) => {
   const onDragEnd: OnDragEndResponder = (result) => {
     if (!result.destination?.index) return;
     if (!result.destination?.index) return;
     void controller.moveField({
     void controller.moveField({
@@ -202,6 +213,7 @@ export const EditRow = ({
             cellCache={controller.databaseViewCache.getRowCache().getCellCache()}
             cellCache={controller.databaseViewCache.getRowCache().getCellCache()}
             fieldController={controller.fieldController}
             fieldController={controller.fieldController}
             onOutsideClick={() => setShowChangeOptionsPopup(false)}
             onOutsideClick={() => setShowChangeOptionsPopup(false)}
+            openOptionDetail={onOpenOptionDetailClick}
           ></CellOptionsPopup>
           ></CellOptionsPopup>
         )}
         )}
         {showDatePicker && editingCell && (
         {showDatePicker && editingCell && (
@@ -214,6 +226,18 @@ export const EditRow = ({
             onOutsideClick={() => setShowDatePicker(false)}
             onOutsideClick={() => setShowDatePicker(false)}
           ></DatePickerPopup>
           ></DatePickerPopup>
         )}
         )}
+        {showEditCellOption && editingCell && (
+          <EditCellOptionPopup
+            top={editCellOptionTop}
+            left={editCellOptionLeft}
+            cellIdentifier={editingCell}
+            cellCache={controller.databaseViewCache.getRowCache().getCellCache()}
+            fieldController={controller.fieldController}
+            onOutsideClick={() => {
+              setShowEditCellOption(false);
+            }}
+          ></EditCellOptionPopup>
+        )}
       </div>
       </div>
     </div>
     </div>
   );
   );