diff --git a/.vscode/settings.json b/.vscode/settings.json index 56f3e77..9c609c2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,10 @@ "*.css": "tailwindcss" }, "cSpell.words": [ + "headlessui", "heroicons", + "konva", + "Tesseract", "wailsjs" ] } \ No newline at end of file diff --git a/core/Consts/Consts.go b/core/Consts/Consts.go index 4f0aef0..aca418b 100644 --- a/core/Consts/Consts.go +++ b/core/Consts/Consts.go @@ -2,17 +2,25 @@ package consts import "textualize/entities" -func GetSuppportedLanguages() []entities.Language { +func GetSupportedLanguages() []entities.Language { return []entities.Language{ { - DisplayName: "English", - ProcessCode: "eng", - TranslateCode: "en", + DisplayName: "English", + ProcessCode: "eng", + TranslateCode: "en", + IsBundledCustom: false, }, { - DisplayName: "Hebrew", - ProcessCode: "heb", - TranslateCode: "he", + DisplayName: "Hebrew - Classic", + ProcessCode: "heb", + TranslateCode: "he", + IsBundledCustom: false, + }, + { + DisplayName: "Hebrew - Rashi", + ProcessCode: "heb_rashi", + TranslateCode: "he", + IsBundledCustom: true, }, } } diff --git a/entities/Language.go b/entities/Language.go index 5dbf4f5..e7b98a4 100644 --- a/entities/Language.go +++ b/entities/Language.go @@ -1,7 +1,8 @@ package entities type Language struct { - DisplayName string `json:"displayName"` - ProcessCode string `json:"processCode"` - TranslateCode string `json:"translateCode"` + DisplayName string `json:"displayName"` + ProcessCode string `json:"processCode"` + TranslateCode string `json:"translateCode"` + IsBundledCustom bool `json:"isBundledCustom"` } diff --git a/entities/ProcessedText.go b/entities/ProcessedText.go index 69f9cda..961105b 100644 --- a/entities/ProcessedText.go +++ b/entities/ProcessedText.go @@ -23,14 +23,12 @@ type ProcessedWord struct { } type ProcessedLine struct { - FullText string `json:"fullText"` - Words []ProcessedWord `json:"words"` + Words []ProcessedWord `json:"words"` } type ProcessedArea struct { Id string `json:"id"` DocumentId string `json:"documentId"` - FullText string `json:"fullText"` Order int `json:"order"` Lines []ProcessedLine `json:"lines"` } diff --git a/frontend/components/DocumentCanvas/Area.tsx b/frontend/components/DocumentCanvas/Area.tsx new file mode 100644 index 0000000..ddd6775 --- /dev/null +++ b/frontend/components/DocumentCanvas/Area.tsx @@ -0,0 +1,90 @@ +'use client' + +import React, { useState } from 'react' +import { Group, Rect } from 'react-konva' +import { entities } from '../../wailsjs/wailsjs/go/models' +import { useProject } from '../../context/Project/provider' +import { KonvaEventObject } from 'konva/lib/Node' +import Konva from 'konva' +import AreaContextMenu from './AreaContextMenu' + +type Props = { + isActive: boolean, + area: entities.Area, + scale: number, + setHoveredOverAreaIds: Function + setHoveredProcessedArea: Function +} + +type coordinates = { x: number, y: number } + +const Area = (props: Props) => { + const { getProcessedAreaById, setSelectedAreaId } = useProject() + const shapeRef = React.useRef(null) + const [isAreaContextMenuOpen, setIsAreaContextMenuOpen] = useState(false) + const [areaContextMenuPosition, setAreaContextMenuPosition] = useState() + + const { area, scale, isActive, setHoveredOverAreaIds, setHoveredProcessedArea } = props + const a = area + const width = (a.endX - a.startX) + const height = (a.endY - a.startY) + + const handleEnterOrLeave = (e: KonvaEventObject) => { + const stage = e.currentTarget.getStage()! + const currentMousePosition = stage.pointerPos + const intersectingNodes = stage.getAllIntersections(currentMousePosition) + const drawnAreas = intersectingNodes.filter(n => n.attrs?.isArea) + const drawnAreasIds = drawnAreas.map(d => d.attrs?.id) + setHoveredOverAreaIds(drawnAreasIds) + + const processedAreaRequests = drawnAreasIds.map(a => getProcessedAreaById(a || '')) + Promise.all(processedAreaRequests).then(responses => { + const validResponses = responses.filter(r => r?.id) as entities.ProcessedArea[] + setHoveredProcessedArea(validResponses || []) + }) + } + + const handleContextMenu = (e: KonvaEventObject) => { + e.evt.preventDefault() + const stage = e.currentTarget.getStage() + const pointerPosition = stage?.getRelativePointerPosition() + if (!pointerPosition) return + + const x = pointerPosition.x + 4 + const y = pointerPosition.y + 4 + setAreaContextMenuPosition({ x, y }) + setIsAreaContextMenuOpen(true) + } + + return + setSelectedAreaId(a.id)} + onContextMenu={handleContextMenu} + isArea /> + {!isAreaContextMenuOpen + ? <> + : + } + +} + +export default Area \ No newline at end of file diff --git a/frontend/components/DocumentCanvas/AreaCanvas.tsx b/frontend/components/DocumentCanvas/AreaCanvas.tsx deleted file mode 100644 index da0b65a..0000000 --- a/frontend/components/DocumentCanvas/AreaCanvas.tsx +++ /dev/null @@ -1,69 +0,0 @@ -'use client' - -import React, { useEffect, useRef } from 'react' -import { useProject } from '../../context/Project/provider' - -type Props = { - width: number, - height: number - zoomLevel: number -} - - -const AreaCanvas = (props: Props) => { - const { getSelectedDocument, selectedAreaId, } = useProject() - const canvas = useRef(null) - - const areas = getSelectedDocument()?.areas - const { width, height, zoomLevel } = props - - - const applyAreasToCanvas = (zoomLevel: number) => { - if (!areas || !areas.length) return - - const canvasContext = canvas.current!.getContext('2d')! - - areas.forEach(a => { - canvasContext.beginPath() - if (a.id !== selectedAreaId) { - canvasContext.setLineDash([4]) - canvasContext.lineWidth = 2 - canvasContext.strokeStyle = '#010101' - } else { - canvasContext.setLineDash([]) - canvasContext.lineWidth = 3 - canvasContext.strokeStyle = '#dc8dec' - } - const width = (a.endX - a.startX) * zoomLevel - const height = (a.endY - a.startY) * zoomLevel - const x = a.startX * zoomLevel - const y = a.startY * zoomLevel - canvasContext.roundRect(x, y, width, height, 4) - canvasContext.stroke() - canvasContext.closePath() - }) - } - - const clearCanvas = () => { - const canvasInstance = canvas.current! - const context = canvasInstance.getContext('2d')! - context.clearRect(0, 0, canvasInstance.width, canvasInstance.height) - } - - const updateSize = (size: { width: number, height: number }) => { - const canvasInstance = canvas.current! - const { width, height } = size - canvasInstance.width = width - canvasInstance.height = height - } - - useEffect(() => { - clearCanvas() - updateSize({ width, height }) - applyAreasToCanvas(zoomLevel) - }, [width, height, zoomLevel, areas]) - - return -} - -export default AreaCanvas diff --git a/frontend/components/DocumentCanvas/AreaContextMenu/index.tsx b/frontend/components/DocumentCanvas/AreaContextMenu/index.tsx new file mode 100644 index 0000000..4f560ce --- /dev/null +++ b/frontend/components/DocumentCanvas/AreaContextMenu/index.tsx @@ -0,0 +1,92 @@ +'use client' + +import React from 'react' +import { entities } from '../../../wailsjs/wailsjs/go/models' +import { Html } from 'react-konva-utils' +import { copyButtonColors, deleteButtonColors, makeFormStyles, makeSharedButtonStyles, reprocessButtonColors, setMutableStylesOnElement, setPosition, setScale } from './styles' +import { useProject } from '../../../context/Project/provider' +import asyncClick from '../../../utils/asyncClick' +import processImageArea from '../../../useCases/processImageArea' + +type Props = { + x: number, + y: number, + scale: number, + area: entities.Area, + setIsAreaContextMenuOpen: Function +} + +/** + * This uses Knova's HTML portal which does not support CSS classes. + * Because of this limitation we have to hack some UX with inline styles. + * @param {Props} props + */ +const AreaContextMenu = (props: Props) => { + const { getProcessedAreaById, requestDeleteAreaById, getSelectedDocument } = useProject() + const { area, setIsAreaContextMenuOpen, scale, x, y } = props + setPosition(x, y) + setScale(scale) + const sharedButtonStyles = makeSharedButtonStyles() + + const handleBlur = (e: React.FocusEvent) => { + console.log(e.relatedTarget) + if (!e.currentTarget.contains(e.relatedTarget)) setIsAreaContextMenuOpen(false) + } + + const handleCopyButtonClick = async () => { + const processedArea = await getProcessedAreaById(area.id) + const wordsOfProcessedArea = processedArea?.lines.flatMap(l => l.words.map(w => w.fullText)) + const fullText = wordsOfProcessedArea?.join(' ') + if (!fullText) return // TODO: change to show notification when copy fails + + await navigator.clipboard.writeText(fullText) + setIsAreaContextMenuOpen(false) + } + + const handleDeleteButtonClick = async () => { + const response = await requestDeleteAreaById(area.id) + if (!response) return // TODO: change to show notification when copy fails + + setIsAreaContextMenuOpen(false) + } + + const handleReprocessButtonClick = async () => { + const documentId = getSelectedDocument()?.id + if (!documentId) return // TODO: change to show notification when copy fails + + setIsAreaContextMenuOpen(false) // TODO: possibly have loading animation and wait until after process + await processImageArea(documentId, area.id) + } + + return +
+ asyncClick(e, handleCopyButtonClick)} + onMouseEnter={(e) => {setMutableStylesOnElement(e, copyButtonColors.hover)} } + onMouseLeave={(e) => {setMutableStylesOnElement(e, copyButtonColors.normal)} }> + Copy Area + + asyncClick(e, handleReprocessButtonClick)} + onMouseEnter={(e) => {setMutableStylesOnElement(e, reprocessButtonColors.hover)} } + onMouseLeave={(e) => {setMutableStylesOnElement(e, reprocessButtonColors.normal)} }> + Reprocess + + asyncClick(e, handleDeleteButtonClick)} + onMouseEnter={(e) => {setMutableStylesOnElement(e, deleteButtonColors.hover)} } + onMouseLeave={(e) => {setMutableStylesOnElement(e, deleteButtonColors.normal)} }> + Delete + +
+ + +} + +export default AreaContextMenu diff --git a/frontend/components/DocumentCanvas/AreaContextMenu/styles.ts b/frontend/components/DocumentCanvas/AreaContextMenu/styles.ts new file mode 100644 index 0000000..12340b0 --- /dev/null +++ b/frontend/components/DocumentCanvas/AreaContextMenu/styles.ts @@ -0,0 +1,90 @@ +import { DetailedHTMLProps, FormHTMLAttributes } from 'react' + +let scale = 1 +const setScale = (newScale: number) => scale = newScale +const getScaled = (value: number) => Math.floor(value / scale) + +let left = 0 +let top = 0 +const setPosition = (x: number, y: number) => { + left = x + top = y +} + +const makeProportionalStyles = () => ({ + fontSize: getScaled(18), + radius: getScaled(6), + formPadding: getScaled(12), + buttonPadding: getScaled(4), + verticalMargin: getScaled(4), + shadowOffset: { + x: getScaled(4), + y: getScaled(4), + color: 'rgba(50, 50, 50, 0.4)', + blur: getScaled(20), + } +}) + +const makeFormStyles = () => { + const proportionalStyles = makeProportionalStyles() + return { + position: 'absolute', + left: `${left}px`, + top: `${top}px`, + textAlign: 'center', + display: 'block', + fontSize: `${proportionalStyles.fontSize}px`, + backgroundColor: 'rgb(229, 231, 235)', + borderRadius: `${proportionalStyles.radius}px`, + borderTopLeftRadius: '0px', + padding: `${proportionalStyles.formPadding}px`, + boxShadow: `${proportionalStyles.shadowOffset.x}px ${proportionalStyles.shadowOffset.y}px ${proportionalStyles.shadowOffset.blur}px ${proportionalStyles.shadowOffset.color}` + } as DetailedHTMLProps, HTMLFormElement> +} + +const makeSharedButtonStyles = () => { + const proportionalStyles = makeProportionalStyles() + return { + display: 'block', + margin: `${proportionalStyles.verticalMargin}px auto`, + width: '100%', + border: 'solid 1px', + borderColor: 'rgb(31, 41, 55)', + borderRadius: `${proportionalStyles.radius}px`, + padding: `${proportionalStyles.buttonPadding}px`, + } +} + +const reprocessButtonColors = { + normal: { color: '#414C61', backgroundColor: '#E5E7EB' }, + hover: { color: '#E5E7EB', backgroundColor: '#9AB3E6' }, +} + +const copyButtonColors = { + normal: { color: '#414C61', backgroundColor: '#E5E7EB' }, + hover: { color: '#E5E7EB', backgroundColor: '#9AB3E6' }, +} + +const deleteButtonColors = { + normal: { color: '#DADCE0', backgroundColor: '#f87171' }, + hover: { color: '#E5E7EB', backgroundColor: '#AD5050' }, +} + +// Awful TS hackery +type styleDeclaration = Partial & { [propName: string]: string }; +const setMutableStylesOnElement = (e: React.MouseEvent, stylesToSet: styleDeclaration) => { + for (const style in stylesToSet) { + (e.currentTarget.style as styleDeclaration)[style] = stylesToSet[style] + } +} + +export { + setScale, + setPosition, + makeFormStyles, + makeSharedButtonStyles, + copyButtonColors, + deleteButtonColors, + reprocessButtonColors, + setMutableStylesOnElement, +} \ No newline at end of file diff --git a/frontend/components/DocumentCanvas/AreaTextPreview.tsx b/frontend/components/DocumentCanvas/AreaTextPreview.tsx deleted file mode 100644 index 6752578..0000000 --- a/frontend/components/DocumentCanvas/AreaTextPreview.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react' -import { entities } from '../../wailsjs/wailsjs/go/models' -import classNames from '../../utils/classNames' - -type Props = { - areas: entities.Area[] - processedArea?: entities.ProcessedArea - zoomLevel: number - setWordToEdit: (props: { word: entities.ProcessedWord, areaId: string }) => void -} - -const AreaTextPreview = ({ areas, processedArea, zoomLevel, setWordToEdit }: Props) => { - if (!processedArea) return <> - - - return
- { - processedArea.lines?.map(l => l.words).flat().map((w, i) => { - const width = Math.floor((w.boundingBox.x1 - w.boundingBox.x0) * zoomLevel) + 2 - const height = Math.floor((w.boundingBox.y1 - w.boundingBox.y0) * zoomLevel) + 2 - return setWordToEdit({ word: w, areaId: processedArea.id })}> - {w.fullText} - - }) - } -
-} - -export default AreaTextPreview diff --git a/frontend/components/DocumentCanvas/Areas.tsx b/frontend/components/DocumentCanvas/Areas.tsx new file mode 100644 index 0000000..b3b5e81 --- /dev/null +++ b/frontend/components/DocumentCanvas/Areas.tsx @@ -0,0 +1,63 @@ +'use client' + +import React, { useState } from 'react' +import { Group } from 'react-konva' +import { useProject } from '../../context/Project/provider' +import { entities } from '../../wailsjs/wailsjs/go/models' +import Area from './Area' +import ProcessedWord from './ProcessedWord' +import EditingWord from './EditingWord' + +type Props = { scale: number } + +const Areas = ({ scale }: Props) => { + const { getSelectedDocument, selectedAreaId } = useProject() + const areas = getSelectedDocument()?.areas || [] + const [hoveredOverAreaIds, setHoveredOverAreaIds] = useState([]) + const [hoveredProcessedAreas, setHoveredProcessedArea] = useState([]) + const [editingWord, setEditingWord] = useState(null) + + const renderEditingWord = () => { + if (!editingWord) return + return + } + + const renderProcessedWords = () => { + if (!hoveredProcessedAreas.length) return + + return hoveredProcessedAreas.map(a => { + const words = a.lines.map(l => l.words).flat() + return words.map((w, index) => ) + }) + } + + const renderAreas = (areas: entities.Area[]) => areas.map((a, index) => { + return + }) + + return + {renderAreas(areas)} + {renderProcessedWords()} + {renderEditingWord()} + +} + +export default Areas + + + diff --git a/frontend/components/DocumentCanvas/CanvasStage.tsx b/frontend/components/DocumentCanvas/CanvasStage.tsx new file mode 100644 index 0000000..3367317 --- /dev/null +++ b/frontend/components/DocumentCanvas/CanvasStage.tsx @@ -0,0 +1,103 @@ +'use client' + +import React, { useRef, useState } from 'react' +import { Stage, Layer, Image, } from 'react-konva' +import { KonvaEventObject } from 'konva/lib/Node' +import Areas from './Areas' +import { useProject } from '../../context/Project/provider' +import useImage from 'use-image' +import { RectangleCoordinates } from './types' +import DrawingArea from './DrawingArea' +import getNormalizedRectToBounds from '../../utils/getNormalizedRectToBounds' +import processImageArea from '../../useCases/processImageArea' + +type Props = { + scale: number, + scaleStep: number, + maxScale: number, + setScale: Function, + size: { width: number, height: number } +} + +let downClickX: number +let downClickY: number +let isDrawing = false + +const CanvasStage = ({ scale, scaleStep, maxScale, setScale, size }: Props) => { + const { getSelectedDocument, requestAddArea, setSelectedAreaId } = useProject() + const [documentImage] = useImage(getSelectedDocument()?.path || '') + const documentRef = useRef(null) + const [drawingAreaRect, setDrawingAreaRect] = useState(null) + + const documentWidth = documentImage?.naturalWidth || 0 + const documentHeight = documentImage?.naturalHeight || 0 + + const handleMouseDown = (e: KonvaEventObject) => { + if (!e.evt.shiftKey) return e.currentTarget.startDrag() + + const position = e.currentTarget.getRelativePointerPosition() + downClickX = position.x + downClickY = position.y + isDrawing = true + } + + const handleMouseMove = (e: KonvaEventObject) => { + const currentPosition = e.currentTarget.getRelativePointerPosition() + if (isDrawing) return setDrawingAreaRect({ + startX: downClickX, + startY: downClickY, + endX: currentPosition.x, + endY: currentPosition.y, + }) + } + + const handleMouseUp = (e: KonvaEventObject) => { + const stage = e.currentTarget + if (stage.isDragging()) stage.stopDrag() + if (isDrawing) isDrawing = false + + if (!drawingAreaRect) return + + const normalizedDrawnRect = getNormalizedRectToBounds(drawingAreaRect, documentWidth, documentHeight, scale) + const selectedDocumentId = getSelectedDocument()!.id + requestAddArea(selectedDocumentId, normalizedDrawnRect).then(addedArea => { + setSelectedAreaId(addedArea.id) + processImageArea(selectedDocumentId, addedArea.id) + }) + + setDrawingAreaRect(null) + } + + const handleWheel = (e: KonvaEventObject) => { + if (!e.evt.ctrlKey) return + + const wheelDelta = e.evt.deltaY + + const shouldAttemptScaleUp = (wheelDelta < 0) && scale < maxScale + if (shouldAttemptScaleUp) setScale(scale + scaleStep) + else if (scale > (scaleStep * 2)) setScale(scale - scaleStep) + } + + return + + Document Image + {(isDrawing && drawingAreaRect) ? : <>} + + + + + +} + +export default CanvasStage diff --git a/frontend/components/DocumentCanvas/DrawingArea.tsx b/frontend/components/DocumentCanvas/DrawingArea.tsx new file mode 100644 index 0000000..047da4f --- /dev/null +++ b/frontend/components/DocumentCanvas/DrawingArea.tsx @@ -0,0 +1,30 @@ +'use client' + +import React from 'react' +import { Rect, } from 'react-konva' +type Props = { + rect: { + startX: number, + startY: number, + endX: number, + endY: number, + }, +} + +const DrawingArea = (props: Props) => { + const { rect } = props + const width = rect.endX - rect.startX + const height = rect.endY - rect.startY + return +} + +export default DrawingArea diff --git a/frontend/components/DocumentCanvas/EditProcessedWord.tsx b/frontend/components/DocumentCanvas/EditProcessedWord.tsx deleted file mode 100644 index c65b0fe..0000000 --- a/frontend/components/DocumentCanvas/EditProcessedWord.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import React, { useRef } from 'react' -import { ipc, entities } from '../../wailsjs/wailsjs/go/models' -import classNames from '../../utils/classNames' -import onEnterHandler from '../../utils/onEnterHandler' -import { useProject } from '../../context/Project/provider' - -type Props = { - zoomLevel: number - processedArea?: entities.ProcessedArea - wordToEdit?: entities.ProcessedWord - setWordToEdit: (props?: { word: entities.ProcessedWord, areaId: string }) => void - setHoveredProcessedArea: (area?: entities.ProcessedArea) => void -} - -const EditProcessedWord = ({ setWordToEdit, zoomLevel, wordToEdit, processedArea, setHoveredProcessedArea }: Props) => { - const { - requestUpdateProcessedWordById, - getProcessedAreaById, - } = useProject() - const editWordInput = useRef(null) - - - if (!wordToEdit || !processedArea) return <> - - const width = Math.floor((wordToEdit.boundingBox.x1 - wordToEdit.boundingBox.x0) * zoomLevel) + 2 - const height = Math.floor(((wordToEdit.boundingBox.y1 - wordToEdit.boundingBox.y0) * zoomLevel) * 2) + 4 - - const handleWordCorrectionSubmit = (wordId: string, newWordValue: string) => { - requestUpdateProcessedWordById(wordId, newWordValue) - .then(res => { - getProcessedAreaById(processedArea.id || '').then(response => { - setHoveredProcessedArea(response) - }) - }) - .catch(console.error) - setWordToEdit(undefined) - } - - return
setWordToEdit(undefined)} - > -
- {wordToEdit.fullText} -
- - e.currentTarget.select()} - onBlur={(e) => handleWordCorrectionSubmit(wordToEdit.id, e.currentTarget.value)} - onKeyDown={(e) => onEnterHandler(e, () => handleWordCorrectionSubmit(wordToEdit.id, e.currentTarget.value))} - /> -
-} - -export default EditProcessedWord \ No newline at end of file diff --git a/frontend/components/DocumentCanvas/EditingWord.tsx b/frontend/components/DocumentCanvas/EditingWord.tsx new file mode 100644 index 0000000..dd507f3 --- /dev/null +++ b/frontend/components/DocumentCanvas/EditingWord.tsx @@ -0,0 +1,51 @@ +import React from 'react' +import { Html } from 'react-konva-utils' +import { entities } from '../../wailsjs/wailsjs/go/models' +import { useProject } from '../../context/Project/provider' +import onEnterHandler from '../../utils/onEnterHandler' + +type Props = { + scale: number, + editingWord: entities.ProcessedWord, + setEditingWord: Function, +} + +const EditingWord = (props: Props) => { + const { requestUpdateProcessedWordById } = useProject() + const { scale, setEditingWord, editingWord } = props + + const handleWordCorrectionSubmit = (wordId: string, newWordValue: string) => { + requestUpdateProcessedWordById(wordId, newWordValue).catch(console.error) + setEditingWord(null) + } + + const { x0, x1, y0, y1 } = editingWord.boundingBox + const left = x0 * scale + const top = y1 * scale + const width = (x1 - x0) * scale + const height = (y1 - y0) * scale + + return + onEnterHandler(e, () => handleWordCorrectionSubmit(editingWord.id, e.currentTarget.value))} + onBlur={(e) => handleWordCorrectionSubmit(editingWord.id, e.currentTarget.value)} + /> + +} + +export default EditingWord \ No newline at end of file diff --git a/frontend/components/DocumentCanvas/ImageCanvas.tsx b/frontend/components/DocumentCanvas/ImageCanvas.tsx deleted file mode 100644 index 685995b..0000000 --- a/frontend/components/DocumentCanvas/ImageCanvas.tsx +++ /dev/null @@ -1,55 +0,0 @@ -'use client' - -import React, { useEffect, useRef } from 'react' -import loadImage from '../../useCases/loadImage' - -type Props = { - zoomLevel: number, - imagePath?: string, - setSize: (size: { width: number, height: number }) => void -} - -const ImageCanvas = (props: Props) => { - const canvas = useRef(null) - const { imagePath, zoomLevel, setSize } = props - - const applyImageToCanvas = async (path: string) => { - const canvasContext = canvas.current!.getContext('2d')! - - let image: HTMLImageElement - try { - image = await loadImage(path) - } catch (err) { - return - } - - const width = image.naturalWidth * zoomLevel - const height = image.naturalHeight * zoomLevel - - updateSize({ width, height }) - - canvasContext.drawImage(image, 0, 0, width, height) - } - - const clearCanvas = () => { - const canvasInstance = canvas.current! - const context = canvasInstance.getContext('2d')! - context.clearRect(0, 0, canvasInstance.width, canvasInstance.height) - } - - const updateSize = (size: { width: number, height: number }) => { - const canvasInstance = canvas.current! - const { width, height } = size - canvasInstance.width = width - canvasInstance.height = height - setSize(size) - } - - useEffect(() => { - if (imagePath) applyImageToCanvas(imagePath) - }, [imagePath, zoomLevel]) - - return -} - -export default ImageCanvas diff --git a/frontend/components/DocumentCanvas/ProcessedWord.tsx b/frontend/components/DocumentCanvas/ProcessedWord.tsx new file mode 100644 index 0000000..d5f5805 --- /dev/null +++ b/frontend/components/DocumentCanvas/ProcessedWord.tsx @@ -0,0 +1,57 @@ +'use client' + +import React from 'react' +import { Group, Rect, Text } from 'react-konva' +import { entities } from '../../wailsjs/wailsjs/go/models' + +type Props = { + area: entities.ProcessedArea, + word: entities.ProcessedWord, + scale: number, + setEditingWord: Function +} + +const ProcessedWord = (props: Props) => { + const { area, scale, word, setEditingWord } = props + const { x0, x1, y0, y1 } = word.boundingBox + + return setEditingWord(word)}> + + + +} + +export default ProcessedWord \ No newline at end of file diff --git a/frontend/components/DocumentCanvas/UiCanvas.tsx b/frontend/components/DocumentCanvas/UiCanvas.tsx deleted file mode 100644 index ddcccf8..0000000 --- a/frontend/components/DocumentCanvas/UiCanvas.tsx +++ /dev/null @@ -1,186 +0,0 @@ -'use client' - -import React, { WheelEvent, useEffect, useRef, useState } from 'react' -import { useProject } from '../../context/Project/provider' -import { entities } from '../../wailsjs/wailsjs/go/models' -import createUiCanvasInteractions from './createUiCanvasInteractions' -import processImageArea from '../../useCases/processImageArea' -import AreaTextPreview from './AreaTextPreview' -import EditProcessedWord from './EditProcessedWord' - -type Props = { - width: number, - height: number - zoomDetails: { currentZoomLevel: number, zoomStep: number, maxZoomLevel: number } - setZoomLevel: (value: number) => void -} - -let interactions: ReturnType | null = null - -let downClickX = 0 -let downClickY = 0 -let isDrawing = false - -const UiCanvas = (props: Props) => { - const { - getSelectedDocument, - getProcessedAreaById, - requestAddArea, - setSelectedAreaId, - } = useProject() - const canvas = useRef(null) - const [hoverOverAreaId, setHoverOverAreaId] = useState('') - const [wordToEdit, setWordToEdit] = useState<{ word: entities.ProcessedWord, areaId: string } | undefined>() - const [hoveredProcessedArea, setHoveredProcessedArea] = useState() - - const areas = getSelectedDocument()?.areas || [] - const { width, height, zoomDetails, setZoomLevel } = props - const { currentZoomLevel } = zoomDetails - - const applyUiCanvasUpdates = () => { - const canvasContext = canvas.current!.getContext('2d')! - - if (!areas || !areas.length) return - - const hoverArea = areas.find(a => a.id === hoverOverAreaId) - if (!hoverArea) return - - canvasContext.beginPath() - canvasContext.setLineDash([]) - canvasContext.lineWidth = 6 - canvasContext.strokeStyle = '#dc8dec' - const width = (hoverArea.endX - hoverArea.startX) * currentZoomLevel - const height = (hoverArea.endY - hoverArea.startY) * currentZoomLevel - const x = hoverArea.startX * currentZoomLevel - const y = hoverArea.startY * currentZoomLevel - canvasContext.roundRect(x, y, width, height, 4) - canvasContext.stroke() - canvasContext.closePath() - } - - const clearCanvas = () => { - const canvasInstance = canvas.current! - const context = canvasInstance.getContext('2d')! - context.clearRect(0, 0, canvasInstance.width, canvasInstance.height) - } - - const handleMouseDown = (e: React.MouseEvent) => { - if (e.nativeEvent.shiftKey) { - downClickX = e.nativeEvent.offsetX - downClickY = e.nativeEvent.offsetY - isDrawing = true - } - } - - const handleMouseMove = (e: React.MouseEvent) => { - if (isDrawing) interactions?.onActivelyDrawArea({ - startX: downClickX, - startY: downClickY, - endX: e.nativeEvent.offsetX, - endY: e.nativeEvent.offsetY, - }) - else interactions?.onHoverOverArea( - e.clientX, - e.clientY, - currentZoomLevel, - areas, - (areaId) => { - if (areaId === hoverOverAreaId) return - - setHoverOverAreaId(areaId || '') - getProcessedAreaById(areaId || '').then(response => { - setHoveredProcessedArea(response) - }) - } - ) - } - - const handleMouseUp = async (e: React.MouseEvent) => { - if (isDrawing) { - const coordinates = { - startMouseX: downClickX, - startMouseY: downClickY, - endMouseX: e.nativeEvent.offsetX, - endMouseY: e.nativeEvent.offsetY, - } - interactions?.onFinishDrawArea(coordinates, currentZoomLevel, - async (startX, startY, endX, endY) => { - const canvasInstance = canvas.current - if (!canvasInstance) return - - const selectedDocumentId = getSelectedDocument()?.id - if (selectedDocumentId) { - const addedArea = await requestAddArea(selectedDocumentId, { startX, startY, endX, endY }) - setSelectedAreaId(addedArea.id) - processImageArea(selectedDocumentId, addedArea.id) - } - - const context = canvasInstance.getContext('2d') - context?.clearRect(0, 0, canvasInstance.width, canvasInstance.height) - isDrawing = false - downClickX = 0 - downClickY = 0 - } - ) - } - } - - const handleWheelEvent = (e: WheelEvent) => { - if (e.ctrlKey) interactions?.onZoom(e.deltaY, zoomDetails, setZoomLevel) - } - - const updateSize = (size: { width: number, height: number }) => { - const canvasInstance = canvas.current! - const { width, height } = size - canvasInstance.width = width - canvasInstance.height = height - } - - - useEffect(() => { - if (!interactions && canvas.current) { - interactions = createUiCanvasInteractions(canvas.current) - } - }, [canvas.current]) - - useEffect(() => { - clearCanvas() - updateSize({ width, height }) - applyUiCanvasUpdates() - }, [width, height, currentZoomLevel, areas]) - - - useEffect(() => { - clearCanvas() - applyUiCanvasUpdates() - }, [hoverOverAreaId]) - - - return <> - - - - - - -} - -export default UiCanvas diff --git a/frontend/components/DocumentCanvas/createUiCanvasInteractions.ts b/frontend/components/DocumentCanvas/createUiCanvasInteractions.ts deleted file mode 100644 index 1840341..0000000 --- a/frontend/components/DocumentCanvas/createUiCanvasInteractions.ts +++ /dev/null @@ -1,79 +0,0 @@ -import isInBounds from '../../utils/isInBounds' -import { entities } from '../../wailsjs/wailsjs/go/models' -import { AddAreaToStoreCallback, HoverOverAreaCallback, MouseCoordinates, RectangleCoordinates, SetZoomCallback, ZoomDetails } from './types' - -/** - * @param uiCanvas - * @returns Various methods to be called during events on the `UiCanvas`. - * Dependencies must be injected, such as state change callbacks. - */ -const createUiCanvasInteractions = (uiCanvas: HTMLCanvasElement) => { - const uiCanvasContext = uiCanvas.getContext('2d')! - - return { - onActivelyDrawArea: (coordinates: RectangleCoordinates) => { - const { startX, startY, endX, endY } = coordinates - - uiCanvasContext.clearRect(0, 0, uiCanvas.width, uiCanvas.height) - uiCanvasContext.beginPath() - const width = endX - startX - const height = endY - startY - uiCanvasContext.rect(startX, startY, width, height) - uiCanvasContext.strokeStyle = '#000' - uiCanvasContext.lineWidth = 2 - uiCanvasContext.stroke() - }, - onFinishDrawArea: (coordinates: MouseCoordinates, zoomLevel: number, addAreaToStoreCallback: AddAreaToStoreCallback) => { - let { startMouseX, endMouseX, startMouseY, endMouseY } = coordinates - - let startX: number, endX: number - if (startMouseX < endMouseX) { - startX = Math.floor(startMouseX / zoomLevel) - endX = Math.floor(endMouseX / zoomLevel) - } else { - startX = Math.floor(endMouseX / zoomLevel) - endX = Math.floor(startMouseX / zoomLevel) - } - - let startY: number, endY: number - if (startMouseY < endMouseY) { - startY = Math.floor(startMouseY / zoomLevel) - endY = Math.floor(endMouseY / zoomLevel) - } else { - startY = Math.floor(endMouseY / zoomLevel) - endY = Math.floor(startMouseY / zoomLevel) - } - - addAreaToStoreCallback(startX, startY, endX, endY) - }, - onZoom: (wheelDelta: number, zoomDetails: ZoomDetails, setZoomCallBack: SetZoomCallback) => { - const { currentZoomLevel, maxZoomLevel, zoomStep } = zoomDetails - - const shouldAttemptToZoomIn = (wheelDelta < 0) && currentZoomLevel < maxZoomLevel - if (shouldAttemptToZoomIn) setZoomCallBack(currentZoomLevel + zoomStep) - else if (currentZoomLevel > (zoomStep * 2)) setZoomCallBack(currentZoomLevel - zoomStep) - }, - onHoverOverArea: (mouseX: number, mouseY: number, zoomLevel: number, areas: entities.Area[], callback: HoverOverAreaCallback) => { - if (!areas.length) return - - const domRect = uiCanvas.getBoundingClientRect() - const x = mouseX - domRect.left - const y = mouseY - domRect.top - const point = { x, y } - - const areaContainingCoords = areas.find(a => { - const bounds = { - startX: a.startX, - startY: a.startY, - endX: a.endX, - endY: a.endY - } - return isInBounds(point, bounds, zoomLevel) - }) - - callback(areaContainingCoords?.id) - }, - } -} - -export default createUiCanvasInteractions diff --git a/frontend/components/DocumentCanvas/index.tsx b/frontend/components/DocumentCanvas/index.tsx index d7ba515..c7762b5 100644 --- a/frontend/components/DocumentCanvas/index.tsx +++ b/frontend/components/DocumentCanvas/index.tsx @@ -1,15 +1,16 @@ 'use client' -import React, { useState } from 'react' +import dynamic from 'next/dynamic' +import React, { useEffect, useRef, useState } from 'react' import { useProject, } from '../../context/Project/provider' import { MagnifyingGlassMinusIcon, MagnifyingGlassPlusIcon } from '@heroicons/react/24/outline' -import classNames from '../../utils/classNames' import LanguageSelect from '../workspace/LanguageSelect' -import ImageCanvas from './ImageCanvas' -import AreaCanvas from './AreaCanvas' -import UiCanvas from './UiCanvas' -const zoomStep = 0.025 +const CanvasStage = dynamic(() => import('./CanvasStage'), { + ssr: false, +}) + +const zoomStep = 0.01 const maxZoomLevel = 4 const DocumentCanvas = () => { @@ -18,9 +19,22 @@ const DocumentCanvas = () => { const [zoomLevel, setZoomLevel] = useState(1) const [size, setSize] = useState({ width: 0, height: 0 }) - const { width, height } = size + const thisRef = useRef(null) - return
+ + const handleWindowResize = () => { + const width = thisRef?.current?.clientWidth || 0 + const height = thisRef?.current?.clientHeight || 0 + setSize({ width, height }) + } + + useEffect(() => { + handleWindowResize() + window.addEventListener('resize', handleWindowResize) + return () => window.removeEventListener('resize', handleWindowResize) + }, [thisRef?.current?.clientWidth, thisRef?.current?.clientHeight]) + + return

{selectedDocument?.name}

@@ -36,21 +50,9 @@ const DocumentCanvas = () => {
-
- - - +
+
} diff --git a/frontend/components/project/Main.tsx b/frontend/components/project/Main.tsx index 0986a7b..65ba38e 100644 --- a/frontend/components/project/Main.tsx +++ b/frontend/components/project/Main.tsx @@ -17,7 +17,7 @@ const MainProject = () => { const [isProjectListModal, setIsProjectListModal] = useState(false) const [canPopoverBeOpen, setCanPopoverBeOpen] = useState(true) - const [avalibleProjects, setAvalibleProjects] = useState([]) + const [availableProjects, setAvailableProjects] = useState([]) const { createNewProject, requestSelectProjectByName } = useProject() const { setSelectedMainPage } = useNavigation() @@ -39,7 +39,7 @@ const MainProject = () => { setCanPopoverBeOpen(false) GetAllLocalProjects().then(response => { console.log(response) - setAvalibleProjects(response) + setAvailableProjects(response) setIsProjectListModal(true) }) }, @@ -73,7 +73,7 @@ const MainProject = () => { {isNewProjectModalOpen ? : ''} - {isProjectListModal ? : '' } + {isProjectListModal ? : '' }
diff --git a/frontend/components/workspace/Sidebar/AreaLineItem.tsx b/frontend/components/workspace/Sidebar/AreaLineItem.tsx index b2ab129..d673aa9 100644 --- a/frontend/components/workspace/Sidebar/AreaLineItem.tsx +++ b/frontend/components/workspace/Sidebar/AreaLineItem.tsx @@ -46,7 +46,8 @@ const AreaLineItem = (props: { area: SidebarArea, documentId: string, index: num const onAreaClick = (areaId: string) => { setSelectedDocumentId(props.documentId) - setSelectedAreaId(areaId) + if (selectedAreaId !== areaId) setSelectedAreaId(areaId) + else setSelectedAreaId('') } const onAreaDoubleClick = (areaId: string) => { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4ea7378..5f3487e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,12 +12,16 @@ "@heroicons/react": "^2.0.13", "@monaco-editor/react": "^4.4.6", "@tailwindcss/forms": "^0.5.3", - "next": "^13.1.1", + "konva": "^9.2.0", + "next": "^13.4.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-konva": "^18.2.9", + "react-konva-utils": "^1.0.4", "react-markdown": "^8.0.5", "rehype-raw": "^6.1.1", "tesseract.js": "^4.0.2", + "use-image": "^1.1.0", "uuid": "^9.0.0" }, "devDependencies": { @@ -429,9 +433,9 @@ } }, "node_modules/@next/env": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.1.1.tgz", - "integrity": "sha512-vFMyXtPjSAiOXOywMojxfKIqE3VWN5RCAx+tT3AS3pcKjMLFTCJFUWsKv8hC+87Z1F4W3r68qTwDFZIFmd5Xkw==" + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.4.tgz", + "integrity": "sha512-q/y7VZj/9YpgzDe64Zi6rY1xPizx80JjlU2BTevlajtaE3w1LqweH1gGgxou2N7hdFosXHjGrI4OUvtFXXhGLg==" }, "node_modules/@next/eslint-plugin-next": { "version": "13.1.1", @@ -442,40 +446,10 @@ "glob": "7.1.7" } }, - "node_modules/@next/swc-android-arm-eabi": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.1.1.tgz", - "integrity": "sha512-qnFCx1kT3JTWhWve4VkeWuZiyjG0b5T6J2iWuin74lORCupdrNukxkq9Pm+Z7PsatxuwVJMhjUoYz7H4cWzx2A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-android-arm64": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.1.1.tgz", - "integrity": "sha512-eCiZhTzjySubNqUnNkQCjU3Fh+ep3C6b5DCM5FKzsTH/3Gr/4Y7EiaPZKILbvnXmhWtKPIdcY6Zjx51t4VeTfA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.1.1.tgz", - "integrity": "sha512-9zRJSSIwER5tu9ADDkPw5rIZ+Np44HTXpYMr0rkM656IvssowPxmhK0rTreC1gpUCYwFsRbxarUJnJsTWiutPg==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.4.tgz", + "integrity": "sha512-xfjgXvp4KalNUKZMHmsFxr1Ug+aGmmO6NWP0uoh4G3WFqP/mJ1xxfww0gMOeMeSq/Jyr5k7DvoZ2Pv+XOITTtw==", "cpu": [ "arm64" ], @@ -488,9 +462,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.1.1.tgz", - "integrity": "sha512-qWr9qEn5nrnlhB0rtjSdR00RRZEtxg4EGvicIipqZWEyayPxhUu6NwKiG8wZiYZCLfJ5KWr66PGSNeDMGlNaiA==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.4.tgz", + "integrity": "sha512-ZY9Ti1hkIwJsxGus3nlubIkvYyB0gNOYxKrfsOrLEqD0I2iCX8D7w8v6QQZ2H+dDl6UT29oeEUdDUNGk4UEpfg==", "cpu": [ "x64" ], @@ -502,40 +476,10 @@ "node": ">= 10" } }, - "node_modules/@next/swc-freebsd-x64": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.1.1.tgz", - "integrity": "sha512-UwP4w/NcQ7V/VJEj3tGVszgb4pyUCt3lzJfUhjDMUmQbzG9LDvgiZgAGMYH6L21MoyAATJQPDGiAMWAPKsmumA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm-gnueabihf": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.1.1.tgz", - "integrity": "sha512-CnsxmKHco9sosBs1XcvCXP845Db+Wx1G0qouV5+Gr+HT/ZlDYEWKoHVDgnJXLVEQzq4FmHddBNGbXvgqM1Gfkg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.1.1.tgz", - "integrity": "sha512-JfDq1eri5Dif+VDpTkONRd083780nsMCOKoFG87wA0sa4xL8LGcXIBAkUGIC1uVy9SMsr2scA9CySLD/i+Oqiw==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.4.tgz", + "integrity": "sha512-+KZnDeMShYkpkqAvGCEDeqYTRADJXc6SY1jWXz+Uo6qWQO/Jd9CoyhTJwRSxvQA16MoYzvILkGaDqirkRNctyA==", "cpu": [ "arm64" ], @@ -548,9 +492,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.1.1.tgz", - "integrity": "sha512-GA67ZbDq2AW0CY07zzGt07M5b5Yaq5qUpFIoW3UFfjOPgb0Sqf3DAW7GtFMK1sF4ROHsRDMGQ9rnT0VM2dVfKA==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.4.tgz", + "integrity": "sha512-evC1twrny2XDT4uOftoubZvW3EG0zs0ZxMwEtu/dDGVRO5n5pT48S8qqEIBGBUZYu/Xx4zzpOkIxx1vpWdE+9A==", "cpu": [ "arm64" ], @@ -563,9 +507,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.1.1.tgz", - "integrity": "sha512-nnjuBrbzvqaOJaV+XgT8/+lmXrSCOt1YYZn/irbDb2fR2QprL6Q7WJNgwsZNxiLSfLdv+2RJGGegBx9sLBEzGA==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.4.tgz", + "integrity": "sha512-PX706XcCHr2FfkyhP2lpf+pX/tUvq6/ke7JYnnr0ykNdEMo+sb7cC/o91gnURh4sPYSiZJhsF2gbIqg9rciOHQ==", "cpu": [ "x64" ], @@ -578,9 +522,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.1.1.tgz", - "integrity": "sha512-CM9xnAQNIZ8zf/igbIT/i3xWbQZYaF397H+JroF5VMOCUleElaMdQLL5riJml8wUfPoN3dtfn2s4peSr3azz/g==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.4.tgz", + "integrity": "sha512-TKUUx3Ftd95JlHV6XagEnqpT204Y+IsEa3awaYIjayn0MOGjgKZMZibqarK3B1FsMSPaieJf2FEAcu9z0yT5aA==", "cpu": [ "x64" ], @@ -593,9 +537,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.1.1.tgz", - "integrity": "sha512-pzUHOGrbgfGgPlOMx9xk3QdPJoRPU+om84hqVoe6u+E0RdwOG0Ho/2UxCgDqmvpUrMab1Deltlt6RqcXFpnigQ==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.4.tgz", + "integrity": "sha512-FP8AadgSq4+HPtim7WBkCMGbhr5vh9FePXiWx9+YOdjwdQocwoCK5ZVC3OW8oh3TWth6iJ0AXJ/yQ1q1cwSZ3A==", "cpu": [ "arm64" ], @@ -608,9 +552,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.1.1.tgz", - "integrity": "sha512-WeX8kVS46aobM9a7Xr/kEPcrTyiwJqQv/tbw6nhJ4fH9xNZ+cEcyPoQkwPo570dCOLz3Zo9S2q0E6lJ/EAUOBg==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.4.tgz", + "integrity": "sha512-3WekVmtuA2MCdcAOrgrI+PuFiFURtSyyrN1I3UPtS0ckR2HtLqyqmS334Eulf15g1/bdwMteePdK363X/Y9JMg==", "cpu": [ "ia32" ], @@ -623,9 +567,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.1.1.tgz", - "integrity": "sha512-mVF0/3/5QAc5EGVnb8ll31nNvf3BWpPY4pBb84tk+BfQglWLqc5AC9q1Ht/YMWiEgs8ALNKEQ3GQnbY0bJF2Gg==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.4.tgz", + "integrity": "sha512-AHRITu/CrlQ+qzoqQtEMfaTu7GHaQ6bziQln/pVWpOYC1wU+Mq6VQQFlsDtMCnDztPZtppAXdvvbNS7pcfRzlw==", "cpu": [ "x64" ], @@ -696,9 +640,9 @@ "dev": true }, "node_modules/@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", + "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "dependencies": { "tslib": "^2.4.0" } @@ -784,6 +728,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-reconciler": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.2.tgz", + "integrity": "sha512-8tu6lHzEgYPlfDf/J6GOQdIc+gs+S2yAqlby3zTsB3SP2svlqTYe5fwZNtZyfactP74ShooP2vvi1BOp9ZemWw==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", @@ -1261,6 +1213,17 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -2999,6 +2962,17 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/its-fine": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.1.1.tgz", + "integrity": "sha512-v1Ia1xl20KbuSGlwoaGsW0oxsw8Be+TrXweidxD9oT/1lAh6O3K3/GIM95Tt6WCiv6W+h2M7RB1TwdoAjQyyKw==", + "dependencies": { + "@types/react-reconciler": "^0.28.0" + }, + "peerDependencies": { + "react": ">=18.0" + } + }, "node_modules/js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", @@ -3084,6 +3058,25 @@ "node": ">=6" } }, + "node_modules/konva": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/konva/-/konva-9.2.0.tgz", + "integrity": "sha512-+woI76Sk+VFVl9z7zPkuTnN2zFpEYg27YWz8BCdQXpt5IS3pdnSPAPQVPPMidcbDi9/G5b/IOIp35/KqMGiYPA==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/lavrton" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/konva" + }, + { + "type": "github", + "url": "https://github.com/sponsors/lavrton" + } + ] + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -3752,49 +3745,47 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, "node_modules/next": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/next/-/next-13.1.1.tgz", - "integrity": "sha512-R5eBAaIa3X7LJeYvv1bMdGnAVF4fVToEjim7MkflceFPuANY3YyvFxXee/A+acrSYwYPvOvf7f6v/BM/48ea5w==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/next/-/next-13.4.4.tgz", + "integrity": "sha512-C5S0ysM0Ily9McL4Jb48nOQHT1BukOWI59uC3X/xCMlYIh9rJZCv7nzG92J6e1cOBqQbKovlpgvHWFmz4eKKEA==", "dependencies": { - "@next/env": "13.1.1", - "@swc/helpers": "0.4.14", + "@next/env": "13.4.4", + "@swc/helpers": "0.5.1", + "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", - "styled-jsx": "5.1.1" + "styled-jsx": "5.1.1", + "zod": "3.21.4" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=14.6.0" + "node": ">=16.8.0" }, "optionalDependencies": { - "@next/swc-android-arm-eabi": "13.1.1", - "@next/swc-android-arm64": "13.1.1", - "@next/swc-darwin-arm64": "13.1.1", - "@next/swc-darwin-x64": "13.1.1", - "@next/swc-freebsd-x64": "13.1.1", - "@next/swc-linux-arm-gnueabihf": "13.1.1", - "@next/swc-linux-arm64-gnu": "13.1.1", - "@next/swc-linux-arm64-musl": "13.1.1", - "@next/swc-linux-x64-gnu": "13.1.1", - "@next/swc-linux-x64-musl": "13.1.1", - "@next/swc-win32-arm64-msvc": "13.1.1", - "@next/swc-win32-ia32-msvc": "13.1.1", - "@next/swc-win32-x64-msvc": "13.1.1" + "@next/swc-darwin-arm64": "13.4.4", + "@next/swc-darwin-x64": "13.4.4", + "@next/swc-linux-arm64-gnu": "13.4.4", + "@next/swc-linux-arm64-musl": "13.4.4", + "@next/swc-linux-x64-gnu": "13.4.4", + "@next/swc-linux-x64-musl": "13.4.4", + "@next/swc-win32-arm64-msvc": "13.4.4", + "@next/swc-win32-ia32-msvc": "13.4.4", + "@next/swc-win32-x64-msvc": "13.4.4" }, "peerDependencies": { + "@opentelemetry/api": "^1.1.0", "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" }, "peerDependenciesMeta": { - "fibers": { + "@opentelemetry/api": { "optional": true }, - "node-sass": { + "fibers": { "optional": true }, "sass": { @@ -4348,6 +4339,50 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-konva": { + "version": "18.2.9", + "resolved": "https://registry.npmjs.org/react-konva/-/react-konva-18.2.9.tgz", + "integrity": "sha512-GfFalHrAlbos23B9vlZkFf+128eimjbenANDtMvTlZskHX25aLt9JxIgX5Cq+QVRrMJBD/SdyIhUxhAuK0A82w==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/lavrton" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/konva" + }, + { + "type": "github", + "url": "https://github.com/sponsors/lavrton" + } + ], + "dependencies": { + "@types/react-reconciler": "^0.28.2", + "its-fine": "^1.1.1", + "react-reconciler": "~0.29.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "konva": "^8.0.1 || ^7.2.5 || ^9.0.0", + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, + "node_modules/react-konva-utils": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-konva-utils/-/react-konva-utils-1.0.4.tgz", + "integrity": "sha512-K1J1K9MoVNGFrUxYt+dn7TUVqpppW3Y0fRcf42Ws1wzTQ2Od4qicCom9jnGxLiwh8zyhYaHAUn3hztgfTyYF7g==", + "dependencies": { + "react-konva": "^18.0.0-0", + "use-image": "^1.1.0" + }, + "peerDependencies": { + "konva": "^8.3.5 || ^9.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, "node_modules/react-markdown": { "version": "8.0.5", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.5.tgz", @@ -4383,6 +4418,21 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "node_modules/react-reconciler": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz", + "integrity": "sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -4689,6 +4739,14 @@ "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string.prototype.matchall": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", @@ -5221,6 +5279,15 @@ "punycode": "^2.1.0" } }, + "node_modules/use-image": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/use-image/-/use-image-1.1.0.tgz", + "integrity": "sha512-+cBHRR/44ZyMUS873O0vbVylgMM0AbdTunEplAWXvIQ2p69h2sIo2Qq74zeUsq6AMo+27e5lERQvXzd1crGiMg==", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -5416,6 +5483,14 @@ "node": "*" } }, + "node_modules/zod": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", @@ -5716,9 +5791,9 @@ } }, "@next/env": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.1.1.tgz", - "integrity": "sha512-vFMyXtPjSAiOXOywMojxfKIqE3VWN5RCAx+tT3AS3pcKjMLFTCJFUWsKv8hC+87Z1F4W3r68qTwDFZIFmd5Xkw==" + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.4.tgz", + "integrity": "sha512-q/y7VZj/9YpgzDe64Zi6rY1xPizx80JjlU2BTevlajtaE3w1LqweH1gGgxou2N7hdFosXHjGrI4OUvtFXXhGLg==" }, "@next/eslint-plugin-next": { "version": "13.1.1", @@ -5729,82 +5804,58 @@ "glob": "7.1.7" } }, - "@next/swc-android-arm-eabi": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.1.1.tgz", - "integrity": "sha512-qnFCx1kT3JTWhWve4VkeWuZiyjG0b5T6J2iWuin74lORCupdrNukxkq9Pm+Z7PsatxuwVJMhjUoYz7H4cWzx2A==", - "optional": true - }, - "@next/swc-android-arm64": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.1.1.tgz", - "integrity": "sha512-eCiZhTzjySubNqUnNkQCjU3Fh+ep3C6b5DCM5FKzsTH/3Gr/4Y7EiaPZKILbvnXmhWtKPIdcY6Zjx51t4VeTfA==", - "optional": true - }, "@next/swc-darwin-arm64": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.1.1.tgz", - "integrity": "sha512-9zRJSSIwER5tu9ADDkPw5rIZ+Np44HTXpYMr0rkM656IvssowPxmhK0rTreC1gpUCYwFsRbxarUJnJsTWiutPg==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.4.tgz", + "integrity": "sha512-xfjgXvp4KalNUKZMHmsFxr1Ug+aGmmO6NWP0uoh4G3WFqP/mJ1xxfww0gMOeMeSq/Jyr5k7DvoZ2Pv+XOITTtw==", "optional": true }, "@next/swc-darwin-x64": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.1.1.tgz", - "integrity": "sha512-qWr9qEn5nrnlhB0rtjSdR00RRZEtxg4EGvicIipqZWEyayPxhUu6NwKiG8wZiYZCLfJ5KWr66PGSNeDMGlNaiA==", - "optional": true - }, - "@next/swc-freebsd-x64": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.1.1.tgz", - "integrity": "sha512-UwP4w/NcQ7V/VJEj3tGVszgb4pyUCt3lzJfUhjDMUmQbzG9LDvgiZgAGMYH6L21MoyAATJQPDGiAMWAPKsmumA==", - "optional": true - }, - "@next/swc-linux-arm-gnueabihf": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.1.1.tgz", - "integrity": "sha512-CnsxmKHco9sosBs1XcvCXP845Db+Wx1G0qouV5+Gr+HT/ZlDYEWKoHVDgnJXLVEQzq4FmHddBNGbXvgqM1Gfkg==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.4.tgz", + "integrity": "sha512-ZY9Ti1hkIwJsxGus3nlubIkvYyB0gNOYxKrfsOrLEqD0I2iCX8D7w8v6QQZ2H+dDl6UT29oeEUdDUNGk4UEpfg==", "optional": true }, "@next/swc-linux-arm64-gnu": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.1.1.tgz", - "integrity": "sha512-JfDq1eri5Dif+VDpTkONRd083780nsMCOKoFG87wA0sa4xL8LGcXIBAkUGIC1uVy9SMsr2scA9CySLD/i+Oqiw==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.4.tgz", + "integrity": "sha512-+KZnDeMShYkpkqAvGCEDeqYTRADJXc6SY1jWXz+Uo6qWQO/Jd9CoyhTJwRSxvQA16MoYzvILkGaDqirkRNctyA==", "optional": true }, "@next/swc-linux-arm64-musl": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.1.1.tgz", - "integrity": "sha512-GA67ZbDq2AW0CY07zzGt07M5b5Yaq5qUpFIoW3UFfjOPgb0Sqf3DAW7GtFMK1sF4ROHsRDMGQ9rnT0VM2dVfKA==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.4.tgz", + "integrity": "sha512-evC1twrny2XDT4uOftoubZvW3EG0zs0ZxMwEtu/dDGVRO5n5pT48S8qqEIBGBUZYu/Xx4zzpOkIxx1vpWdE+9A==", "optional": true }, "@next/swc-linux-x64-gnu": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.1.1.tgz", - "integrity": "sha512-nnjuBrbzvqaOJaV+XgT8/+lmXrSCOt1YYZn/irbDb2fR2QprL6Q7WJNgwsZNxiLSfLdv+2RJGGegBx9sLBEzGA==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.4.tgz", + "integrity": "sha512-PX706XcCHr2FfkyhP2lpf+pX/tUvq6/ke7JYnnr0ykNdEMo+sb7cC/o91gnURh4sPYSiZJhsF2gbIqg9rciOHQ==", "optional": true }, "@next/swc-linux-x64-musl": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.1.1.tgz", - "integrity": "sha512-CM9xnAQNIZ8zf/igbIT/i3xWbQZYaF397H+JroF5VMOCUleElaMdQLL5riJml8wUfPoN3dtfn2s4peSr3azz/g==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.4.tgz", + "integrity": "sha512-TKUUx3Ftd95JlHV6XagEnqpT204Y+IsEa3awaYIjayn0MOGjgKZMZibqarK3B1FsMSPaieJf2FEAcu9z0yT5aA==", "optional": true }, "@next/swc-win32-arm64-msvc": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.1.1.tgz", - "integrity": "sha512-pzUHOGrbgfGgPlOMx9xk3QdPJoRPU+om84hqVoe6u+E0RdwOG0Ho/2UxCgDqmvpUrMab1Deltlt6RqcXFpnigQ==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.4.tgz", + "integrity": "sha512-FP8AadgSq4+HPtim7WBkCMGbhr5vh9FePXiWx9+YOdjwdQocwoCK5ZVC3OW8oh3TWth6iJ0AXJ/yQ1q1cwSZ3A==", "optional": true }, "@next/swc-win32-ia32-msvc": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.1.1.tgz", - "integrity": "sha512-WeX8kVS46aobM9a7Xr/kEPcrTyiwJqQv/tbw6nhJ4fH9xNZ+cEcyPoQkwPo570dCOLz3Zo9S2q0E6lJ/EAUOBg==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.4.tgz", + "integrity": "sha512-3WekVmtuA2MCdcAOrgrI+PuFiFURtSyyrN1I3UPtS0ckR2HtLqyqmS334Eulf15g1/bdwMteePdK363X/Y9JMg==", "optional": true }, "@next/swc-win32-x64-msvc": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.1.1.tgz", - "integrity": "sha512-mVF0/3/5QAc5EGVnb8ll31nNvf3BWpPY4pBb84tk+BfQglWLqc5AC9q1Ht/YMWiEgs8ALNKEQ3GQnbY0bJF2Gg==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.4.tgz", + "integrity": "sha512-AHRITu/CrlQ+qzoqQtEMfaTu7GHaQ6bziQln/pVWpOYC1wU+Mq6VQQFlsDtMCnDztPZtppAXdvvbNS7pcfRzlw==", "optional": true }, "@nodelib/fs.scandir": { @@ -5851,9 +5902,9 @@ "dev": true }, "@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", + "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "requires": { "tslib": "^2.4.0" } @@ -5936,6 +5987,14 @@ "@types/react": "*" } }, + "@types/react-reconciler": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.2.tgz", + "integrity": "sha512-8tu6lHzEgYPlfDf/J6GOQdIc+gs+S2yAqlby3zTsB3SP2svlqTYe5fwZNtZyfactP74ShooP2vvi1BOp9ZemWw==", + "requires": { + "@types/react": "*" + } + }, "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", @@ -6254,6 +6313,14 @@ "update-browserslist-db": "^1.0.9" } }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "requires": { + "streamsearch": "^1.1.0" + } + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -7492,6 +7559,14 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "its-fine": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.1.1.tgz", + "integrity": "sha512-v1Ia1xl20KbuSGlwoaGsW0oxsw8Be+TrXweidxD9oT/1lAh6O3K3/GIM95Tt6WCiv6W+h2M7RB1TwdoAjQyyKw==", + "requires": { + "@types/react-reconciler": "^0.28.0" + } + }, "js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", @@ -7555,6 +7630,11 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" }, + "konva": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/konva/-/konva-9.2.0.tgz", + "integrity": "sha512-+woI76Sk+VFVl9z7zPkuTnN2zFpEYg27YWz8BCdQXpt5IS3pdnSPAPQVPPMidcbDi9/G5b/IOIp35/KqMGiYPA==" + }, "language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -7949,28 +8029,26 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, "next": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/next/-/next-13.1.1.tgz", - "integrity": "sha512-R5eBAaIa3X7LJeYvv1bMdGnAVF4fVToEjim7MkflceFPuANY3YyvFxXee/A+acrSYwYPvOvf7f6v/BM/48ea5w==", + "version": "13.4.4", + "resolved": "https://registry.npmjs.org/next/-/next-13.4.4.tgz", + "integrity": "sha512-C5S0ysM0Ily9McL4Jb48nOQHT1BukOWI59uC3X/xCMlYIh9rJZCv7nzG92J6e1cOBqQbKovlpgvHWFmz4eKKEA==", "requires": { - "@next/env": "13.1.1", - "@next/swc-android-arm-eabi": "13.1.1", - "@next/swc-android-arm64": "13.1.1", - "@next/swc-darwin-arm64": "13.1.1", - "@next/swc-darwin-x64": "13.1.1", - "@next/swc-freebsd-x64": "13.1.1", - "@next/swc-linux-arm-gnueabihf": "13.1.1", - "@next/swc-linux-arm64-gnu": "13.1.1", - "@next/swc-linux-arm64-musl": "13.1.1", - "@next/swc-linux-x64-gnu": "13.1.1", - "@next/swc-linux-x64-musl": "13.1.1", - "@next/swc-win32-arm64-msvc": "13.1.1", - "@next/swc-win32-ia32-msvc": "13.1.1", - "@next/swc-win32-x64-msvc": "13.1.1", - "@swc/helpers": "0.4.14", + "@next/env": "13.4.4", + "@next/swc-darwin-arm64": "13.4.4", + "@next/swc-darwin-x64": "13.4.4", + "@next/swc-linux-arm64-gnu": "13.4.4", + "@next/swc-linux-arm64-musl": "13.4.4", + "@next/swc-linux-x64-gnu": "13.4.4", + "@next/swc-linux-x64-musl": "13.4.4", + "@next/swc-win32-arm64-msvc": "13.4.4", + "@next/swc-win32-ia32-msvc": "13.4.4", + "@next/swc-win32-x64-msvc": "13.4.4", + "@swc/helpers": "0.5.1", + "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", - "styled-jsx": "5.1.1" + "styled-jsx": "5.1.1", + "zod": "3.21.4" }, "dependencies": { "postcss": { @@ -8310,6 +8388,26 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-konva": { + "version": "18.2.9", + "resolved": "https://registry.npmjs.org/react-konva/-/react-konva-18.2.9.tgz", + "integrity": "sha512-GfFalHrAlbos23B9vlZkFf+128eimjbenANDtMvTlZskHX25aLt9JxIgX5Cq+QVRrMJBD/SdyIhUxhAuK0A82w==", + "requires": { + "@types/react-reconciler": "^0.28.2", + "its-fine": "^1.1.1", + "react-reconciler": "~0.29.0", + "scheduler": "^0.23.0" + } + }, + "react-konva-utils": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-konva-utils/-/react-konva-utils-1.0.4.tgz", + "integrity": "sha512-K1J1K9MoVNGFrUxYt+dn7TUVqpppW3Y0fRcf42Ws1wzTQ2Od4qicCom9jnGxLiwh8zyhYaHAUn3hztgfTyYF7g==", + "requires": { + "react-konva": "^18.0.0-0", + "use-image": "^1.1.0" + } + }, "react-markdown": { "version": "8.0.5", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.5.tgz", @@ -8339,6 +8437,15 @@ } } }, + "react-reconciler": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz", + "integrity": "sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -8553,6 +8660,11 @@ "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + }, "string.prototype.matchall": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", @@ -8927,6 +9039,12 @@ "punycode": "^2.1.0" } }, + "use-image": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/use-image/-/use-image-1.1.0.tgz", + "integrity": "sha512-+cBHRR/44ZyMUS873O0vbVylgMM0AbdTunEplAWXvIQ2p69h2sIo2Qq74zeUsq6AMo+27e5lERQvXzd1crGiMg==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -9070,6 +9188,11 @@ "resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz", "integrity": "sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==" }, + "zod": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==" + }, "zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index ab9c759..27af04d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,12 +17,16 @@ "@heroicons/react": "^2.0.13", "@monaco-editor/react": "^4.4.6", "@tailwindcss/forms": "^0.5.3", - "next": "^13.1.1", + "konva": "^9.2.0", + "next": "^13.4.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-konva": "^18.2.9", + "react-konva-utils": "^1.0.4", "react-markdown": "^8.0.5", "rehype-raw": "^6.1.1", "tesseract.js": "^4.0.2", + "use-image": "^1.1.0", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/frontend/package.json.md5 b/frontend/package.json.md5 index 66810ab..549dcc1 100755 --- a/frontend/package.json.md5 +++ b/frontend/package.json.md5 @@ -1 +1 @@ -2415a78ef8f325df057b22f577cbbe50 \ No newline at end of file +e331f957a49840160190db6ea894d0b5 \ No newline at end of file diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 649639e..2271053 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -3,15 +3,15 @@ import { AppProps } from 'next/app' import { ProjectProvider } from '../context/Project/provider' import '../styles/globals.css' -import { ipc } from '../wailsjs/wailsjs/go/models' +import { entities } from '../wailsjs/wailsjs/go/models' import '../styles/globals.css' import { NavigationProvidor } from '../context/Navigation/provider' import { mainPages, workspaces } from '../context/Navigation/types' const initialProjectProps = { id: '', - documents: [] as ipc.Document[], - groups: [] as ipc.Group[] + documents: [] as entities.Document[], + groups: [] as entities.Group[] } const initialNavigationProps = { diff --git a/frontend/public/customLanguages/heb_rashi.traineddata b/frontend/public/customLanguages/heb_rashi.traineddata new file mode 100644 index 0000000..bf90654 Binary files /dev/null and b/frontend/public/customLanguages/heb_rashi.traineddata differ diff --git a/frontend/useCases/processImageArea.ts b/frontend/useCases/processImageArea.ts index 33a1d69..695ceb8 100644 --- a/frontend/useCases/processImageArea.ts +++ b/frontend/useCases/processImageArea.ts @@ -16,8 +16,18 @@ const processImageArea = async (documentId: string, areaId: string) => { const { path } = foundDocument const imageData = await loadImage(path) + let workerOptions: Partial = {} + if (foundDocument.defaultLanguage.isBundledCustom) { + workerOptions = { + langPath: '/customLanguages', + gzip: false, + logger: m => console.log(m) + } + } + + const worker = await createWorker(workerOptions) const scheduler = createScheduler() - const worker = await createWorker() + await worker.loadLanguage(processLanguage) await worker.initialize(processLanguage) scheduler.addWorker(worker) diff --git a/frontend/utils/asyncClick.ts b/frontend/utils/asyncClick.ts new file mode 100644 index 0000000..e59d1b3 --- /dev/null +++ b/frontend/utils/asyncClick.ts @@ -0,0 +1,6 @@ +const asyncClick = (e: React.MouseEvent, callback: (e: React.MouseEvent) => Promise) => { + e.preventDefault() + callback(e) +} + +export default asyncClick diff --git a/frontend/utils/getNormalizedRectToBounds.ts b/frontend/utils/getNormalizedRectToBounds.ts new file mode 100644 index 0000000..67d8b98 --- /dev/null +++ b/frontend/utils/getNormalizedRectToBounds.ts @@ -0,0 +1,30 @@ +import { RectangleCoordinates } from '../components/DocumentCanvas/types' + +const getNormalizedRectToBounds = (rect: RectangleCoordinates, width: number, height: number, scale: number = 1): RectangleCoordinates => { + let startX: number, endX: number + if (rect.startX < rect.endX) { + startX = Math.floor(rect.startX / scale) + endX = Math.floor(rect.endX / scale) + } else { + startX = Math.floor(rect.endX / scale) + endX = Math.floor(rect.startX / scale) + } + + let startY: number, endY: number + if (rect.startY < rect.endY) { + startY = Math.floor(rect.startY / scale) + endY = Math.floor(rect.endY / scale) + } else { + startY = Math.floor(rect.endY / scale) + endY = Math.floor(rect.startY / scale) + } + + if (startX < 0) startX = 0 + if (startY < 0) startY = 0 + if (endX > width) endX = width + if (endY > height) endY = height + + return { startX, startY, endX, endY } +} + +export default getNormalizedRectToBounds \ No newline at end of file diff --git a/frontend/utils/getSupportedLanguages.ts b/frontend/utils/getSupportedLanguages.ts index 1e7dfc6..7b97c97 100644 --- a/frontend/utils/getSupportedLanguages.ts +++ b/frontend/utils/getSupportedLanguages.ts @@ -1,7 +1,7 @@ -import { GetSuppportedLanguages } from '../wailsjs/wailsjs/go/ipc/Channel' +import { GetSupportedLanguages } from '../wailsjs/wailsjs/go/ipc/Channel' const getSupportedLanguages = async () => { - const response = await GetSuppportedLanguages() + const response = await GetSupportedLanguages() return response } diff --git a/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts b/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts index 5522215..acdb95c 100755 --- a/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts +++ b/frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts @@ -21,7 +21,7 @@ export function GetProcessedAreasByDocumentId(arg1:string):Promise; -export function GetSuppportedLanguages():Promise>; +export function GetSupportedLanguages():Promise>; export function GetUserMarkdownByDocumentId(arg1:string):Promise; diff --git a/frontend/wailsjs/wailsjs/go/ipc/Channel.js b/frontend/wailsjs/wailsjs/go/ipc/Channel.js index af6b702..317e990 100755 --- a/frontend/wailsjs/wailsjs/go/ipc/Channel.js +++ b/frontend/wailsjs/wailsjs/go/ipc/Channel.js @@ -38,8 +38,8 @@ export function GetProjectByName(arg1) { return window['go']['ipc']['Channel']['GetProjectByName'](arg1); } -export function GetSuppportedLanguages() { - return window['go']['ipc']['Channel']['GetSuppportedLanguages'](); +export function GetSupportedLanguages() { + return window['go']['ipc']['Channel']['GetSupportedLanguages'](); } export function GetUserMarkdownByDocumentId(arg1) { diff --git a/frontend/wailsjs/wailsjs/go/models.ts b/frontend/wailsjs/wailsjs/go/models.ts index 3170e4f..8230fb8 100755 --- a/frontend/wailsjs/wailsjs/go/models.ts +++ b/frontend/wailsjs/wailsjs/go/models.ts @@ -4,6 +4,7 @@ export namespace entities { displayName: string; processCode: string; translateCode: string; + isBundledCustom: boolean; static createFrom(source: any = {}) { return new Language(source); @@ -14,6 +15,7 @@ export namespace entities { this.displayName = source["displayName"]; this.processCode = source["processCode"]; this.translateCode = source["translateCode"]; + this.isBundledCustom = source["isBundledCustom"]; } } export class Area { @@ -276,7 +278,6 @@ export namespace entities { } } export class ProcessedLine { - fullText: string; words: ProcessedWord[]; static createFrom(source: any = {}) { @@ -285,7 +286,6 @@ export namespace entities { constructor(source: any = {}) { if ('string' === typeof source) source = JSON.parse(source); - this.fullText = source["fullText"]; this.words = this.convertValues(source["words"], ProcessedWord); } @@ -310,7 +310,6 @@ export namespace entities { export class ProcessedArea { id: string; documentId: string; - fullText: string; order: number; lines: ProcessedLine[]; @@ -322,7 +321,6 @@ export namespace entities { if ('string' === typeof source) source = JSON.parse(source); this.id = source["id"]; this.documentId = source["documentId"]; - this.fullText = source["fullText"]; this.order = source["order"]; this.lines = this.convertValues(source["lines"], ProcessedLine); } diff --git a/frontend/wailsjs/wailsjs/runtime/runtime.d.ts b/frontend/wailsjs/wailsjs/runtime/runtime.d.ts index 4006807..a3723f9 100644 --- a/frontend/wailsjs/wailsjs/runtime/runtime.d.ts +++ b/frontend/wailsjs/wailsjs/runtime/runtime.d.ts @@ -225,3 +225,11 @@ export function Hide(): void; // [Show](https://wails.io/docs/reference/runtime/intro#show) // Shows the application. export function Show(): void; + +// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext) +// Returns the current text stored on clipboard +export function ClipboardGetText(): Promise; + +// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext) +// Sets a text on the clipboard +export function ClipboardSetText(text: string): Promise; diff --git a/frontend/wailsjs/wailsjs/runtime/runtime.js b/frontend/wailsjs/wailsjs/runtime/runtime.js index b9be812..bd4f371 100644 --- a/frontend/wailsjs/wailsjs/runtime/runtime.js +++ b/frontend/wailsjs/wailsjs/runtime/runtime.js @@ -37,11 +37,11 @@ export function LogFatal(message) { } export function EventsOnMultiple(eventName, callback, maxCallbacks) { - window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); + return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); } export function EventsOn(eventName, callback) { - EventsOnMultiple(eventName, callback, -1); + return EventsOnMultiple(eventName, callback, -1); } export function EventsOff(eventName, ...additionalEventNames) { @@ -49,7 +49,7 @@ export function EventsOff(eventName, ...additionalEventNames) { } export function EventsOnce(eventName, callback) { - EventsOnMultiple(eventName, callback, 1); + return EventsOnMultiple(eventName, callback, 1); } export function EventsEmit(eventName) { @@ -192,3 +192,11 @@ export function Hide() { export function Show() { window.runtime.Show(); } + +export function ClipboardGetText() { + return window.runtime.ClipboardGetText(); +} + +export function ClipboardSetText(text) { + return window.runtime.ClipboardSetText(text); +} \ No newline at end of file diff --git a/go.mod b/go.mod index 4d5fd5e..24596d4 100644 --- a/go.mod +++ b/go.mod @@ -6,13 +6,12 @@ go 1.18 require ( github.com/google/uuid v1.3.0 - github.com/wailsapp/wails/v2 v2.3.1 + github.com/wailsapp/wails/v2 v2.5.1 ) require ( github.com/bep/debounce v1.2.1 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/imdario/mergo v0.3.13 // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect github.com/labstack/echo/v4 v4.9.0 // indirect github.com/labstack/gommon v0.4.0 // indirect @@ -30,7 +29,7 @@ require ( github.com/wailsapp/mimetype v1.4.1 // indirect golang.org/x/crypto v0.4.0 // indirect golang.org/x/exp v0.0.0-20221207211629-99ab8fa1c11f // indirect - golang.org/x/net v0.4.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect ) diff --git a/go.sum b/go.sum index 56372b8..34e34da 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,6 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY= @@ -52,15 +50,15 @@ github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52 github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= -github.com/wailsapp/wails/v2 v2.3.1 h1:ZJz+pyIBKyASkgO8JO31NuHO1gTTHmvwiHYHwei1CqM= -github.com/wailsapp/wails/v2 v2.3.1/go.mod h1:zlNLI0E2c2qA6miiuAHtp0Bac8FaGH0tlhA19OssR/8= +github.com/wailsapp/wails/v2 v2.5.1 h1:mfG+2kWqQXYOwdgI43HEILjOZDXbk5woPYI3jP2b+js= +github.com/wailsapp/wails/v2 v2.5.1/go.mod h1:jbOZbcr/zm79PxXxAjP8UoVlDd9wLW3uDs+isIthDfs= golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= golang.org/x/exp v0.0.0-20221207211629-99ab8fa1c11f h1:90Jq/vvGVDsqj8QqCynjFw9MCerDguSMODLYII416Y8= golang.org/x/exp v0.0.0-20221207211629-99ab8fa1c11f/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -70,15 +68,14 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/ipc/Session.go b/ipc/Session.go index 3bb4b1d..2b06d75 100644 --- a/ipc/Session.go +++ b/ipc/Session.go @@ -192,7 +192,7 @@ func (c *Channel) RequestChangeSessionProjectByName(projectName string) bool { return session.GetInstance().Project.Id == foundProject.Id } -func (c *Channel) GetSuppportedLanguages() []entities.Language { - supportedLanguages := consts.GetSuppportedLanguages() +func (c *Channel) GetSupportedLanguages() []entities.Language { + supportedLanguages := consts.GetSupportedLanguages() return supportedLanguages }