Skip to content

Commit

Permalink
Merge branch 'main' into ajf/formula-array-literals
Browse files Browse the repository at this point in the history
  • Loading branch information
davidkircos authored Mar 4, 2023
2 parents 9c84f17 + 6a57136 commit d89480e
Show file tree
Hide file tree
Showing 18 changed files with 352 additions and 53 deletions.
42 changes: 34 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"lodash.debounce": "^4.0.8",
"monaco-editor": "^0.31.1",
"numerable": "^0.3.15",
"papaparse": "^5.3.2",
"pixi-viewport": "^4.37.0",
"pixi.js": "^6.5.1",
"quadratic-core": "file:quadratic-core/pkg",
Expand Down Expand Up @@ -102,6 +103,7 @@
"devDependencies": {
"@playwright/test": "^1.22.2",
"@types/lodash.debounce": "^4.0.7",
"@types/papaparse": "^5.3.7",
"concurrently": "^6.3.0",
"electron": "^23.0.0",
"electron-is-dev": "^2.0.0",
Expand Down
6 changes: 6 additions & 0 deletions src/atoms/showCSVImportHelpAtom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { atom } from 'recoil';

export const showCSVImportHelpAtom = atom({
key: 'showCSVImportHelpState', // unique ID (with respect to other atoms/selectors)
default: false,
});
48 changes: 48 additions & 0 deletions src/grid/actions/insertData/insertCSV.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Coordinate } from '../../../gridGL/types/size';
import { SheetController } from '../../controller/sheetController';
// import { Cell } from '../../sheet/gridTypes';
// import { updateCellAndDCells } from '../updateCellAndDCells';
import * as Papa from 'papaparse';
import { updateCellAndDCells } from '../updateCellAndDCells';
import { Cell } from '../../sheet/gridTypes';

export const InsertCSV = (props: {
file: File;
insertAtCellLocation: Coordinate;
sheetController: SheetController;
reportError: (error: string) => void;
}) => {
const { file } = props;
props.sheetController.start_transaction();

let rowIndex = 0;
Papa.parse(file, {
error: function (error, File) {
props.reportError(error.name + ': ' + error.message);
},
complete: function () {
props.sheetController.end_transaction();
},
step: function (row) {
const cellsToInsert: Cell[] = [];

//@ts-expect-error
row.data.forEach((text: string, cellIndex: number) => {
cellsToInsert.push({
value: text.trim(),
type: 'TEXT',
x: props.insertAtCellLocation.x + cellIndex,
y: props.insertAtCellLocation.y + rowIndex,
last_modified: new Date().toISOString(),
});
});
rowIndex++;

updateCellAndDCells({
starting_cells: cellsToInsert,
sheetController: props.sheetController,
create_transaction: false,
});
},
});
};
5 changes: 5 additions & 0 deletions src/gridGL/interaction/keyboard/keyboardViewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ export function keyboardViewport(options: {
return true;
}

if (event.code === 'Escape') {
if (presentationMode) setPresentationMode(false);
return true;
}

if ((event.metaKey || event.ctrlKey) && event.code === 'KeyB') {
changeBold(!(format.bold === true));
return true;
Expand Down
11 changes: 11 additions & 0 deletions src/quadratic/QuadraticApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,22 @@ import { GetCellsDBSetSheet } from '../grid/sheet/Cells/GetCellsDB';
import { localFiles } from '../grid/sheet/localFiles';
import { SheetController } from '../grid/controller/sheetController';
import init, { hello } from 'quadratic-core';
import { useGridSettings } from '../ui/menus/TopBar/SubMenus/useGridSettings';

export const QuadraticApp = () => {
const { loading, incrementLoadingCount } = useLoading();
const [sheet_controller] = useState<SheetController>(new SheetController());
const sheet = sheet_controller.sheet;
const { setPresentationMode } = useGridSettings();
const [settingsReset, setSettingsReset] = useState(false);

// reset presentation mode when app starts
useEffect(() => {
if (!settingsReset) {
setPresentationMode(false);
setSettingsReset(true);
}
}, [setPresentationMode, settingsReset, setSettingsReset]);

// Loading Effect
useEffect(() => {
Expand Down
8 changes: 7 additions & 1 deletion src/ui/QuadraticUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import { useEffect, useState } from 'react';
import { PixiApp } from '../gridGL/pixiApp/PixiApp';
import { SheetController } from '../grid/controller/sheetController';
import CellTypeMenu from './menus/CellTypeMenu';
import { FileUploadWrapper } from './components/FileUploadWrapper';
import { useGridSettings } from './menus/TopBar/SubMenus/useGridSettings';
import PresentationModeHint from './components/PresentationModeHint';
import { CSVImportHelpMessage } from './overlays/CSVImportHelpMessage';

interface Props {
sheetController: SheetController;
Expand Down Expand Up @@ -61,10 +63,14 @@ export default function QuadraticUI(props: Props) {
position: 'relative',
}}
>
<QuadraticGrid sheetController={sheetController} app={app} />
<FileUploadWrapper sheetController={sheetController} app={app}>
<QuadraticGrid sheetController={sheetController} app={app} />
</FileUploadWrapper>
<CodeEditor editorInteractionState={editorInteractionState} sheet_controller={sheetController} />
</div>

<CSVImportHelpMessage></CSVImportHelpMessage>

{!presentationMode && <BottomBar sheet={sheetController.sheet} />}
{presentationMode && <PresentationModeHint />}
</div>
Expand Down
115 changes: 115 additions & 0 deletions src/ui/components/FileUploadWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { useState, DragEvent, useRef } from 'react';
import { useRecoilState } from 'recoil';
import { InsertCSV } from '../../grid/actions/insertData/insertCSV';
import { SheetController } from '../../grid/controller/sheetController';
import { PixiApp } from '../../gridGL/pixiApp/PixiApp';
import { Coordinate } from '../../gridGL/types/size';
import { gridInteractionStateAtom } from '../../atoms/gridInteractionStateAtom';
import debounce from 'lodash.debounce';
import { QuadraticSnackBar } from './QuadraticSnackBar';

interface Props {
sheetController: SheetController;
app: PixiApp;
}

export const FileUploadWrapper = (props: React.PropsWithChildren<Props>) => {
const { app } = props;
// drag state
const [dragActive, setDragActive] = useState(false);
const divRef = useRef<HTMLDivElement>(null);
const [interactionState, setInteractionState] = useRecoilState(gridInteractionStateAtom);

const [errorMessage, setErrorMessage] = useState<string | undefined>(undefined);

const moveCursor = debounce((e: DragEvent<HTMLDivElement>): void => {
const clientBoudingRect = divRef?.current?.getBoundingClientRect();
const world = app.viewport.toWorld(
e.pageX - (clientBoudingRect?.left || 0),
e.pageY - (clientBoudingRect?.top || 0)
);
const { column, row } = props.sheetController.sheet.gridOffsets.getRowColumnFromWorld(world.x, world.y);
setInteractionState({
...interactionState,
cursorPosition: { x: column, y: row },
keyboardMovePosition: { x: column, y: row },
multiCursorPosition: {
originPosition: { x: column, y: row },
terminalPosition: { x: column, y: row },
},
});
}, 100);

// handle drag events
const handleDrag = function (e: DragEvent<HTMLDivElement>) {
e.preventDefault();
e.stopPropagation();
if (e.type === 'dragenter' || e.type === 'dragover') {
setDragActive(true);

moveCursor(e);
} else if (e.type === 'dragleave') {
setDragActive(false);
}
};

// triggers when file is dropped
const handleDrop = async (e: DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
setDragActive(false);

if (e.dataTransfer.files && e.dataTransfer.files[0]) {
const file = e.dataTransfer.files[0];
if (file.type === 'text/csv' || file.type === 'text/tab-separated-values') {
const clientBoudingRect = divRef?.current?.getBoundingClientRect();
const world = app.viewport.toWorld(
e.pageX - (clientBoudingRect?.left || 0),
e.pageY - (clientBoudingRect?.top || 0)
);
const { column, row } = props.sheetController.sheet.gridOffsets.getRowColumnFromWorld(world.x, world.y);

InsertCSV({
sheetController: props.sheetController,
file: file,
insertAtCellLocation: { x: column, y: row } as Coordinate,
reportError: setErrorMessage,
});
} else {
setErrorMessage('File type not supported. Please upload a CSV file.');
}
}
};

return (
<div ref={divRef} onDragEnter={handleDrag} style={{ flex: 1 }}>
{props.children}
{dragActive && (
<div
id="drag-file-element"
onDragEnter={handleDrag}
onDragLeave={handleDrag}
onDragOver={handleDrag}
onDrop={handleDrop}
style={{
position: 'absolute',
width: '100%',
height: '100%',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px',
opacity: '0',
}}
></div>
)}
<QuadraticSnackBar
open={errorMessage !== undefined}
onClose={() => {
setErrorMessage(undefined);
}}
message={errorMessage}
/>
</div>
);
};
10 changes: 4 additions & 6 deletions src/ui/components/PresentationModeHint.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useState, useEffect } from 'react';
import { Snackbar } from '@mui/material';
import { useGridSettings } from '../menus/TopBar/SubMenus/useGridSettings';
import { KeyboardSymbols } from '../../helpers/keyboardSymbols';
import { QuadraticSnackBar } from './QuadraticSnackBar';

export default function PresentationModeHint() {
const { presentationMode } = useGridSettings();
Expand All @@ -14,14 +13,13 @@ export default function PresentationModeHint() {
}, [presentationMode]);

return (
<Snackbar
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
<QuadraticSnackBar
open={open}
onClose={() => {
setOpen(false);
}}
autoHideDuration={5000}
message={`Press ${KeyboardSymbols.Command}.” to exit presentation mode.`}
autoHideDuration={4000}
message={`Press "ESC" to exit presentation mode.`}
/>
);
}
12 changes: 12 additions & 0 deletions src/ui/components/QuadraticSnackBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Fade, Snackbar, SnackbarProps } from '@mui/material';

export const QuadraticSnackBar = (props: SnackbarProps) => {
return (
<Snackbar
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
autoHideDuration={4000}
TransitionComponent={Fade}
{...props}
/>
);
};
Loading

0 comments on commit d89480e

Please sign in to comment.