From 08b3c9d1ac418c1171c6179a7ee1fa861c91e78e Mon Sep 17 00:00:00 2001 From: jialin Date: Mon, 17 Mar 2025 20:24:21 +0800 Subject: [PATCH] fix: remove TODO tips in locales --- .../image-editor/hooks/use-drawing.ts | 10 +- src/components/image-editor/index.less | 4 + src/components/image-editor/index.tsx | 146 ++++++++++-------- src/locales/README.md | 18 +-- src/locales/ru-RU/models.ts | 19 ++- src/locales/ru-RU/playground.ts | 14 +- .../llmodels/components/advance-config.tsx | 10 +- 7 files changed, 131 insertions(+), 90 deletions(-) diff --git a/src/components/image-editor/hooks/use-drawing.ts b/src/components/image-editor/hooks/use-drawing.ts index 8ad7f4d9..7007121c 100644 --- a/src/components/image-editor/hooks/use-drawing.ts +++ b/src/components/image-editor/hooks/use-drawing.ts @@ -31,6 +31,7 @@ export default function useDrawing(props: { const autoScale = useRef(1); const baseScale = useRef(1); const contentPos = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); + const maskStorkeRef = useRef([]); const disabled = useMemo(() => { return isDisabled || invertMask || !!maskUpload?.length; @@ -40,6 +41,10 @@ export default function useDrawing(props: { strokesRef.current = strokes; }; + const setMaskStrokes = (strokes: Stroke[]) => { + maskStorkeRef.current = strokes; + }; + const inpaintArea = useCallback( (data: Uint8ClampedArray) => { for (let i = 0; i < data.length; i += 4) { @@ -61,7 +66,7 @@ export default function useDrawing(props: { }, []); const generateMask = useCallback(() => { - if (strokesRef.current.length === 0) { + if (strokesRef.current.length === 0 && maskStorkeRef.current.length === 0) { return null; } const overlayCanvas = overlayCanvasRef.current!; @@ -180,7 +185,6 @@ export default function useDrawing(props: { stroke.forEach((point, i) => { const { x, y } = getTransformedPoint(point.x, point.y); - console.log('Drawing point:'); ctx.lineWidth = getTransformLineWidth(point.lineWidth); if (i === 0) { ctx.moveTo(x, y); @@ -374,6 +378,8 @@ export default function useDrawing(props: { mouseDownState, autoScale, baseScale, + maskStorkeRef, + setMaskStrokes, fitView, setStrokes, resetCanvas, diff --git a/src/components/image-editor/index.less b/src/components/image-editor/index.less index 60ff835f..68f663f8 100644 --- a/src/components/image-editor/index.less +++ b/src/components/image-editor/index.less @@ -21,6 +21,10 @@ cursor: none !important; } + .overlay-canvas.overlay-canvas--disabled:hover { + cursor: default !important; + } + .upload-mask { &:hover { .close-btn { diff --git a/src/components/image-editor/index.tsx b/src/components/image-editor/index.tsx index aad54a95..aa75dbc0 100644 --- a/src/components/image-editor/index.tsx +++ b/src/components/image-editor/index.tsx @@ -1,3 +1,4 @@ +import classNames from 'classnames'; import dayjs from 'dayjs'; import React, { forwardRef, @@ -56,6 +57,7 @@ const CanvasImageEditor: React.FC = forwardRef( const translatePos = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); const negativeMaskRef = useRef(false); const [invertMask, setInvertMask] = useState(false); + const timer = useRef(null); const { canvasRef, @@ -66,6 +68,8 @@ const CanvasImageEditor: React.FC = forwardRef( mouseDownState, autoScale, baseScale, + maskStorkeRef, + setMaskStrokes, draw, drawStroke, startDrawing, @@ -131,20 +135,25 @@ const CanvasImageEditor: React.FC = forwardRef( options: { lineWidth?: number; color: string; - compositeOperation: 'source-over' | 'destination-out'; } ) => { - const { color, compositeOperation } = options; - - ctx.globalCompositeOperation = compositeOperation; + const { color } = options; stroke.forEach((point) => { const { x, y } = getTransformedPoint(point.x, point.y); - ctx.save(); const width = getTransformLineWidth(point.lineWidth); - ctx.fillStyle = color; + ctx.save(); + + // erase the previous stroke + ctx.globalCompositeOperation = 'destination-out'; ctx.fillRect(x - width / 2, y - width / 2, width, width); + + // draw the new stroke + ctx.globalCompositeOperation = 'source-over'; + ctx.fillStyle = color; + ctx.fillRect(x - width / 2, y - width / 2, width, width); + ctx.restore(); }); }, @@ -159,76 +168,81 @@ const CanvasImageEditor: React.FC = forwardRef( console.log('Resetting strokes', currentStroke.current); }, []); - const redrawStrokes = useCallback( - (strokes: Stroke[], type?: string) => { - console.log('Redrawing strokes:', strokes, type); - clearOverlayCanvas(); - if (!strokes.length) { - return; - } + const loadMaskPixs = (strokes: Stroke[]) => { + clearOverlayCanvas(); + if (!strokes.length) { + return; + } + console.log('loadin mask pixs:'); + const overlayCanvas = overlayCanvasRef.current!; + const overlayCtx = overlayCanvas!.getContext('2d')!; - const overlayCanvas = overlayCanvasRef.current!; + setTransform(); - const overlayCtx = overlayCanvas!.getContext('2d')!; - - // clear offscreen canvas - - setTransform(); - - strokes?.forEach((stroke: Point[], index) => { - overlayCtx.save(); - drawStroke(overlayCtx, stroke, { - color: COLOR, - compositeOperation: 'destination-out' - }); - - drawStroke(overlayCtx, stroke, { - color: COLOR, - compositeOperation: 'source-over' - }); - overlayCtx.restore(); + strokes?.forEach((stroke: Point[], index) => { + drawFillRect(overlayCtx, stroke, { + color: COLOR }); - }, - [drawStroke] - ); + }); + }; + const redrawStrokes = (strokes: Stroke[], type?: string) => { + console.log('Redrawing strokes:', strokes, type); + clearOverlayCanvas(); + if (!strokes.length) { + return; + } - const loadMaskPixs = useCallback( - (strokes: Stroke[], type?: string) => { - clearOverlayCanvas(); - if (!strokes.length) { - return; - } - console.log('loadin mask pixs:'); - const overlayCanvas = overlayCanvasRef.current!; - const overlayCtx = overlayCanvas!.getContext('2d')!; + const overlayCanvas = overlayCanvasRef.current!; - setTransform(); + const overlayCtx = overlayCanvas!.getContext('2d')!; - strokes?.forEach((stroke: Point[], index) => { - overlayCtx.save(); - drawFillRect(overlayCtx, stroke, { - color: COLOR, - compositeOperation: 'destination-out' - }); + // clear offscreen canvas - drawFillRect(overlayCtx, stroke, { - color: COLOR, - compositeOperation: 'source-over' - }); - overlayCtx.restore(); + setTransform(); + overlayCtx.save(); + loadMaskPixs(maskStorkeRef.current); + + strokes?.forEach((stroke: Point[], index) => { + drawStroke(overlayCtx, stroke, { + color: COLOR, + compositeOperation: 'destination-out' }); - }, - [drawFillRect] - ); + + drawStroke(overlayCtx, stroke, { + color: COLOR, + compositeOperation: 'source-over' + }); + }); + overlayCtx.restore(); + }; const undo = () => { - if (strokesRef.current.length === 0) return; + if ( + strokesRef.current.length === 0 && + maskStorkeRef.current.length === 0 + ) { + clearOverlayCanvas(); + return; + } const newStrokes = strokesRef.current.slice(0, -1); - console.log('New strokes:', newStrokes, strokesRef.current); setStrokes(newStrokes); - redrawStrokes(newStrokes); + console.log( + 'newstrokes=======', + newStrokes.length, + maskStorkeRef.current.length + ); + + if (strokesRef.current.length) { + clearTimeout(timer.current); + timer.current = setTimeout(() => { + redrawStrokes(strokesRef.current); + }, 100); + } else if (maskStorkeRef.current.length) { + loadMaskPixs(maskStorkeRef.current); + setMaskStrokes([]); + } }; const downloadOriginImage = () => { @@ -424,6 +438,7 @@ const CanvasImageEditor: React.FC = forwardRef( // mouse up window.addEventListener('mouseup', handleMouseUp); return () => { + clearTimeout(timer.current); window.removeEventListener('keydown', handleUndoShortcut); window.removeEventListener('mousedown', handleMouseDown); window.removeEventListener('mouseup', handleMouseUp); @@ -439,7 +454,8 @@ const CanvasImageEditor: React.FC = forwardRef( useImperativeHandle(ref, () => ({ clearMask: handleDeleteMask, loadMaskPixs(strokes: Stroke[]) { - setStrokes(strokes); + setMaskStrokes(strokes); + setStrokes([]); loadMaskPixs(strokes); } })); @@ -494,7 +510,9 @@ const CanvasImageEditor: React.FC = forwardRef( { mouseDownState.current = true; diff --git a/src/locales/README.md b/src/locales/README.md index f87b2877..8bb11502 100644 --- a/src/locales/README.md +++ b/src/locales/README.md @@ -24,24 +24,14 @@ To add a new language configuration, follow these steps: - Open the `.ts` file in the **new directory**. - For each key-value pair: + - If a translation is available, replace the value with the translated text. - - If no translation is available yet, **replace the value with** `TODO: Translate key ""`. - - This ensures that the key is visible for contributors to know exactly what needs to be translated. + - If no translation is available, keep the `English` value as default. -**Example:** - -```ts -export default { - 'playground.image.mask.upload': - 'TODO: Translate key "playground.image.mask.upload"', - 'welcome.message': 'TODO: Translate key "welcome.message"' -}; -``` - -- **Important**: The `TODO` message should include the original key in quotes so that contributors can easily identify which key needs translation without needing to look at the code itself. +- **Note**: Keeping the English text as the default ensures the application remains functional even if some translations are missing. ## 4. **Finalize the Configuration** - Review and ensure all translations are complete. -- If any translations are missing, contributors can later replace `"TODO: Translate key '...'` with the correct translation. +- If any translations are missing, they will default to `English`. - Your new language configuration is now ready for use! diff --git a/src/locales/ru-RU/models.ts b/src/locales/ru-RU/models.ts index b1fb358a..40179631 100644 --- a/src/locales/ru-RU/models.ts +++ b/src/locales/ru-RU/models.ts @@ -81,7 +81,7 @@ export default { 'models.form.filePath': 'Путь к модели', 'models.form.backendVersion': 'Версия бэкенда', 'models.form.backendVersion.tips': - 'TODO: Translate key "models.form.backendVersion.tips"', + 'To use the desired version of vLLM/llama-box/vox-box, the system will automatically create a virtual environment in the online environment to install the corresponding version. After a GPUStack upgrade, the backend version will remain fixed. {link}', 'models.form.gpuselector': 'Селектор GPU', 'models.form.backend.llamabox': 'Для моделей формата GGUF. Поддержка Linux, macOS и Windows.', @@ -110,10 +110,17 @@ export default { 'models.table.vllmAcrossworker': 'vLLM между воркерами', 'models.form.releases': 'Релизы', 'models.form.moreparameters': 'Описание параметров', - 'models.table.vram.allocated': - 'TODO: Translate key "models.table.vram.allocated"', + 'models.table.vram.allocated': 'Allocated VRAM', 'models.form.backend.warning': - 'TODO: Translate key "models.form.backend.warning"', - 'models.form.backend.warning.llamabox': - "TODO: Translate key 'models.form.backend.warning.llamabox'" + 'The backend for GGUF format models uses llama-box.', + 'models.form.backend.warning.llamabox': `To use the llama-box backend, specify the full path to the model file (e.g.,/data/models/model.gguf). For sharded models, provide the path to the first shard (e.g.,/data/models/model-00001-of-00004.gguf).` }; + +// ========== To-Do: Translate Keys (Remove After Translation) ========== + +// 1. models.form.backendVersion.tips +// 2. models.form.backend.warning +// 3. models.form.backend.warning.llamabox +// 4. models.table.vram.allocated + +// ========== End of To-Do List ========== diff --git a/src/locales/ru-RU/playground.ts b/src/locales/ru-RU/playground.ts index 851e1ff6..64432666 100644 --- a/src/locales/ru-RU/playground.ts +++ b/src/locales/ru-RU/playground.ts @@ -137,14 +137,22 @@ export default { 'playground.image.edit': 'Редактировать', 'playground.image.fitview': 'Подогнать размер', 'playground.chat.aithought': 'Рассуждение (CoT)', - 'playground.chat.thinking': 'TODO: Translate key "playground.chat.thinking"', + 'playground.chat.thinking': 'Thinking...', 'playground.image.mask.uploaded': 'Маска загружена', 'playground.image.mask.upload': - 'TODO: Translate key "playground.image.mask.upload"', + 'Upload Mask: No additional drawing allowed after upload.', 'playground.params.frequency_penalty.tips': `Число от -2.0 до 2.0. Положительные значения снижают вероятность повторения токенов, уже часто встречающихся в тексте, уменьшая склонность модели дословно повторять одни и те же фразы.`, 'playground.params.presence_penalty.tips': `Число от -2.0 до 2.0. Положительные значения снижают вероятность повторения любых токенов, присутствующих в тексте, повышая склонность модели к обсуждению новых тем.`, 'playground.image.origin': 'Оригинал', 'playground.image.mask': 'Маска', 'playground.image.negativeMask.tips': - 'TODO: Translate key "playground.image.negativeMask.tips"' + '1. After selection, no further masking can be drawn; therefore, you should draw the mask first and then check the option.\n 2. Once a mask image is uploaded, no further masks can be generated.' }; + +// ========== To-Do: Translate Keys (Remove After Translation) ========== + +// 1. playground.chat.thinking +// 2. playground.image.mask.upload +// 3. playground.image.negativeMask.tips + +// ========== End of To-Do List ========== diff --git a/src/pages/llmodels/components/advance-config.tsx b/src/pages/llmodels/components/advance-config.tsx index db64689c..63d8a685 100644 --- a/src/pages/llmodels/components/advance-config.tsx +++ b/src/pages/llmodels/components/advance-config.tsx @@ -183,6 +183,14 @@ const AdvanceConfig: React.FC = (props) => { return ; }; + const tagRender = (props: any) => { + if (props.isMaxTag) { + return props.label; + } + const parent = _.split(props.value, '__RC_CASCADER_SPLIT__')?.[0]; + return `${parent} / ${props?.label}`; + }; + const collapseItems = useMemo(() => { const children = ( <> @@ -313,7 +321,7 @@ const AdvanceConfig: React.FC = (props) => { onClose={props.onClose} maxWidth={240} > - {props.label} + {tagRender(props)} ); }}