Skip to content

Commit

Permalink
Merge pull request #665 from Lemoncode/dev
Browse files Browse the repository at this point in the history
update copy paste, plus icons
  • Loading branch information
brauliodiez authored Jan 18, 2025
2 parents 61f4e2f + 3e9b54e commit e22adfa
Show file tree
Hide file tree
Showing 17 changed files with 196 additions and 8 deletions.
1 change: 1 addition & 0 deletions public/icons/book.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/bookopen.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/books.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/calendarplus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/chalkboard.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/clockuser.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/minuscircle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/person.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/pluscircle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/userfocus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/userlist.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/core/providers/canvas/canvas.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ export interface CanvasContextModel {
setCanvasSize: (canvasDimensions: CanvasSize) => void;
customColors: (string | null)[];
updateColorSlot: (color: string, index: number) => void;
dropRef: React.MutableRefObject<HTMLDivElement | null>;
setDropRef: (dropRef: React.MutableRefObject<HTMLDivElement | null>) => void;
}

export const APP_CONSTANTS = {
Expand Down
9 changes: 8 additions & 1 deletion src/core/providers/canvas/canvas.provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,16 @@ export const CanvasProvider: React.FC<Props> = props => {
});
};

const [dropRef, setDropRef] = React.useState<
React.MutableRefObject<HTMLDivElement | null>
>(React.useRef<HTMLDivElement>(null));

const { copyShapeToClipboard, pasteShapeFromClipboard, canCopy, canPaste } =
useClipboard(
pasteShapes,
document.pages[document.activePageIndex].shapes,
selectionInfo
selectionInfo,
dropRef
);

const createNewFullDocument = () => {
Expand Down Expand Up @@ -362,6 +367,8 @@ export const CanvasProvider: React.FC<Props> = props => {
setCanvasSize: setCanvasSize,
customColors,
updateColorSlot,
dropRef,
setDropRef,
}}
>
{children}
Expand Down
15 changes: 13 additions & 2 deletions src/core/providers/canvas/use-clipboard.hook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
export const useClipboard = (
pasteShapes: (shapes: ShapeModel[]) => void,
shapes: ShapeModel[],
selectionInfo: { selectedShapesIds: string[] | null }
selectionInfo: { selectedShapesIds: string[] | null },
dropRef: React.MutableRefObject<HTMLDivElement | null>
) => {
const [clipboardShape, setClipboardShape] = useState<ShapeModel[] | null>(
null
Expand All @@ -30,11 +31,21 @@ export const useClipboard = (
}
};

const updateClipboardShapes = (shapes: ShapeModel[]) => {
copyCount.current = 0;
clipboardShapesRef.current = [...shapes];
};

const pasteShapeFromClipboard = () => {
if (clipboardShapesRef.current) {
const newShapes: ShapeModel[] = cloneShapes(clipboardShapesRef.current);
validateShapes(newShapes);
adjustShapesPosition(newShapes, copyCount.current);
adjustShapesPosition(
newShapes,
copyCount.current,
dropRef,
updateClipboardShapes
);
pasteShapes(newShapes);
copyCount.current++;
}
Expand Down
4 changes: 4 additions & 0 deletions src/pods/canvas/canvas.pod.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const CanvasPod = () => {
updateShapePosition,
stageRef,
canvasSize,
setDropRef,
} = useCanvasContext();

const {
Expand All @@ -52,6 +53,9 @@ export const CanvasPod = () => {

const { isDraggedOver, dropRef } = useDropShape();
useMonitorShape(dropRef, addNewShapeAndSetSelected);
useEffect(() => {
if (dropRef.current) setDropRef(dropRef);
}, [dropRef, setDropRef]);

const getSelectedShapeKonvaId = (): string[] => {
let result: string[] = [];
Expand Down
97 changes: 92 additions & 5 deletions src/pods/canvas/clipboard.utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import cloneDeep from 'lodash.clonedeep';
import { ShapeModel } from '@/core/model';
import invariant from 'tiny-invariant';
interface Displacement {
x: number;
y: number;
}
interface Viewport {
xMinVisible: number;
xMaxVisible: number;
yMinVisible: number;
yMaxVisible: number;
}

export const findShapesById = (
shapeIds: string[],
Expand All @@ -17,12 +27,89 @@ export const cloneShape = (shape: ShapeModel): ShapeModel => {
return cloneDeep(shape);
};

export const adjustShapesPosition = (shapes: ShapeModel[], copyCount: number) =>
shapes.map(shape => adjustShapePosition(shape, copyCount));
function areAllShapesFullyVisible(
shapes: ShapeModel[],
viewport: Viewport,
copyCount: number
): boolean {
return shapes.every(shape => {
const offsetX = 20 * copyCount;
const offsetY = 20 * copyCount;
const newX = shape.x + offsetX;
const newY = shape.y + offsetY;
const left = newX;
const right = newX + shape.width;
const top = newY;
const bottom = newY + shape.height;

export const adjustShapePosition = (shape: ShapeModel, copyCount: number) => {
shape.x += 20 * copyCount;
shape.y += 20 * copyCount;
return (
left >= viewport.xMinVisible &&
right <= viewport.xMaxVisible &&
top >= viewport.yMinVisible &&
bottom <= viewport.yMaxVisible
);
});
}

export const adjustShapesPosition = (
shapes: ShapeModel[],
copyCount: number,
dropRef: React.MutableRefObject<HTMLDivElement | null>,
updateClipboardShapes: (shapes: ShapeModel[]) => void
) => {
const container = dropRef.current;
if (!container) return;

const containerRect = container.getBoundingClientRect();
const scrollLeft = container.scrollLeft;
const scrollTop = container.scrollTop;

const viewPort: Viewport = {
xMinVisible: scrollLeft,
xMaxVisible: scrollLeft + containerRect.width,
yMinVisible: scrollTop,
yMaxVisible: scrollTop + containerRect.height,
};

const allVisible = areAllShapesFullyVisible(shapes, viewPort, copyCount);

if (allVisible) {
shapes.forEach(shape => {
adjustShapePosition(shape, copyCount);
});
} else {
const shape0 = shapes[0];
const oldX0 = shape0.x + 20 * copyCount;
const oldY0 = shape0.y + 20 * copyCount;

const centerX = scrollLeft + containerRect.width / 2;
const centerY = scrollTop + containerRect.height / 2;

const targetX0 = centerX - shape0.width / 2;
const targetY0 = centerY - shape0.height / 2;

const displacement: Displacement = {
x: targetX0 - oldX0,
y: targetY0 - oldY0,
};

shapes.forEach(shape => {
adjustShapePosition(shape, copyCount, displacement);
});
}

updateClipboardShapes(shapes);
};

export const adjustShapePosition = (
shape: ShapeModel,
copyCount: number,
d: Displacement = { x: 0, y: 0 }
) => {
const originalX = shape.x + 20 * copyCount;
const originalY = shape.y + 20 * copyCount;
shape.x = originalX + d.x;
shape.y = originalY + d.y;
};

export const validateShapes = (shapes: ShapeModel[]) => {
Expand Down
66 changes: 66 additions & 0 deletions src/pods/properties/components/icon-selector/modal/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2302,4 +2302,70 @@ export const iconCollection: IconInfo[] = [
searchTerms: ['rocket', 'launch', 'space', 'fly'],
categories: ['IT'],
},
{
name: 'Books',
filename: 'books.svg',
searchTerms: ['books', 'library', 'knowledge', 'read'],
categories: ['IT'],
},
{
name: 'Chalkboard',
filename: 'chalkboard.svg',
searchTerms: ['chalkboard', 'blackboard', 'school', 'teach', 'learn'],
categories: ['IT'],
},
{
name: 'Book',
filename: 'book.svg',
searchTerms: ['book', 'library', 'knowledge', 'read'],
categories: ['IT'],
},
{
name: 'Book open',
filename: 'bookopen.svg',
searchTerms: ['book', 'open', 'library', 'knowledge', 'read'],
categories: ['IT'],
},
{
name: 'User list',
filename: 'userlist.svg',
searchTerms: ['user', 'list', 'people', 'group', 'team'],
categories: ['IT'],
},
{
name: 'Person',
filename: 'person.svg',
searchTerms: ['person', 'user', 'human', 'profile', 'individual'],
categories: ['IT'],
},
{
name: 'User focus',
filename: 'userfocus.svg',
searchTerms: ['user', 'focus', 'human', 'profile', 'emphasis'],
categories: ['IT'],
},
{
name: 'Clock user',
filename: 'clockuser.svg',
searchTerms: ['clock', 'user', 'human', 'timetable', 'schedule'],
categories: ['IT'],
},
{
name: 'Plus circle',
filename: 'pluscircle.svg',
searchTerms: ['plus', 'circle', 'add', 'create', 'new', 'more'],
categories: ['IT'],
},
{
name: 'Minus circle',
filename: 'minuscircle.svg',
searchTerms: ['minus', 'circle', 'remove', 'delete', 'less'],
categories: ['IT'],
},
{
name: 'Calendar plus',
filename: 'calendarplus.svg',
searchTerms: ['calendar', 'plus', 'add', 'create', 'new'],
categories: ['IT'],
},
];

0 comments on commit e22adfa

Please sign in to comment.