diff --git a/CHANGELOG.md b/CHANGELOG.md index 78f1992..0dbe4df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + +- Added image map editor for creating and editing interactive image map areas in the File Manager. + ### Changed - Refactored admin module-generator source builders to compose imports and source sections through diff --git a/apps/admin/src/core/FileManager/config/menu.ts b/apps/admin/src/core/FileManager/config/menu.ts index a039a9c..4bc9329 100644 --- a/apps/admin/src/core/FileManager/config/menu.ts +++ b/apps/admin/src/core/FileManager/config/menu.ts @@ -1,4 +1,4 @@ -import { FolderOpen } from 'lucide-react'; +import { FolderOpen, Wrench } from 'lucide-react'; import { IntlShape } from 'react-intl'; import { MenuItem } from '#app/config/types'; @@ -12,9 +12,20 @@ export const createFileManagerMenu = (intl: IntlShape): MenuItem => ({ permissions: ['file_manager.view'] }, { - title: intl.formatMessage({ id: 'FILE_MANAGER.IMAGE_EDITOR.TITLE' }), - path: '/file-manager/editor/image/-/', - permissions: ['file_manager.view'] + title: intl.formatMessage({ id: 'FILE_MANAGER.TOOLS.TITLE' }), + icon: Wrench, + children: [ + { + title: intl.formatMessage({ id: 'FILE_MANAGER.IMAGE_EDITOR.TITLE' }), + path: '/file-manager/tools/image-editor/-/', + permissions: ['file_manager.view'] + }, + { + title: intl.formatMessage({ id: 'FILE_MANAGER.IMAGE_MAP.TITLE' }), + path: '/file-manager/tools/image-map/-/', + permissions: ['file_manager.view'] + } + ] }, { title: intl.formatMessage({ id: 'FILE_MANAGER.SETTINGS' }), diff --git a/apps/admin/src/core/FileManager/config/routing.tsx b/apps/admin/src/core/FileManager/config/routing.tsx index ec5936d..b5b19c9 100755 --- a/apps/admin/src/core/FileManager/config/routing.tsx +++ b/apps/admin/src/core/FileManager/config/routing.tsx @@ -5,6 +5,7 @@ import DriveExplorerPage from '../pages/DriveExplorerPage'; import DriveSettingsPage from '../pages/DriveSettingsPage'; import DriveViewerPage from '../pages/DriveViewerPage'; import ImageEditorPage from '../pages/ImageEditorPage'; +import ImageMapPage from '../pages/ImageMapPage'; function Routing() { const navigate = useNavigate(); @@ -19,7 +20,8 @@ function Routing() { } /> - } /> + } /> + } /> navigate(-1)} />} diff --git a/apps/admin/src/core/FileManager/config/translation/en.json b/apps/admin/src/core/FileManager/config/translation/en.json index d9a6b0d..726adfc 100644 --- a/apps/admin/src/core/FileManager/config/translation/en.json +++ b/apps/admin/src/core/FileManager/config/translation/en.json @@ -1,5 +1,6 @@ { "FILE_MANAGER.MENU.TITLE": "File Manager", + "FILE_MANAGER.TOOLS.TITLE": "Tools", "FILE_MANAGER.SETTINGS": "Settings", "FILE_MANAGER.SETTINGS.TITLE": "File Manager Settings", "FILE_MANAGER.SETTINGS.DESCRIPTION": "Customize your workspace to better manage and navigate your files. Adjust how your items are displayed, change icon dimensions, and optimize the spacing for your specific screen size.", @@ -53,6 +54,7 @@ "FILE_MANAGER.DRIVE.ACTION.BACK": "Back", "FILE_MANAGER.DRIVE.ACTION.CROP": "Crop", "FILE_MANAGER.DRIVE.ACTION.RESIZE": "Resize", + "FILE_MANAGER.DRIVE.ACTION.MAP": "Map", "FILE_MANAGER.DRIVE.ACTION.CANCEL": "Cancel", "FILE_MANAGER.DRIVE.ACTION.CREATE": "Create", "FILE_MANAGER.DRIVE.ACTION.SUBMIT": "Submit", @@ -124,5 +126,21 @@ "FILE_MANAGER.FILE_DETAILS.SIZE": "Size", "FILE_MANAGER.FILE_DETAILS.FILE_NAME": "Name", "FILE_MANAGER.FILE_DETAILS.LAST_MODIFIED": "Last modified", - "FILE_MANAGER.FILE_DETAILS.URL": "URL" + "FILE_MANAGER.FILE_DETAILS.URL": "URL", + + "FILE_MANAGER.IMAGE_MAP.TITLE": "Image Map", + "FILE_MANAGER.IMAGE_MAP.AREAS.TITLE": "Areas", + "FILE_MANAGER.IMAGE_MAP.AREAS.ITEM": "Area", + "FILE_MANAGER.IMAGE_MAP.AREAS.ADD": "Add area", + "FILE_MANAGER.IMAGE_MAP.AREAS.REMOVE": "Remove area", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.TITLE": "Selected area", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.SHAPE": "Shape", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.URL": "URL", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.TITLE_FIELD": "Title", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.TITLE_PLACEHOLDER": "Area title", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.TARGET": "Target", + "FILE_MANAGER.IMAGE_MAP.CODE_PREVIEW.TITLE": "Code preview", + "FILE_MANAGER.IMAGE_MAP.SHAPE.RECTANGLE": "Rectangle", + "FILE_MANAGER.IMAGE_MAP.SHAPE.CIRCLE": "Circle", + "FILE_MANAGER.IMAGE_MAP.SHAPE.POLYGON": "Polygon" } diff --git a/apps/admin/src/core/FileManager/config/translation/uk.json b/apps/admin/src/core/FileManager/config/translation/uk.json index d9811c0..73f75a1 100644 --- a/apps/admin/src/core/FileManager/config/translation/uk.json +++ b/apps/admin/src/core/FileManager/config/translation/uk.json @@ -1,5 +1,6 @@ { "FILE_MANAGER.MENU.TITLE": "Файловий Менеджер", + "FILE_MANAGER.TOOLS.TITLE": "Інструменти", "FILE_MANAGER.SETTINGS": "Налаштування", "FILE_MANAGER.SETTINGS.TITLE": "Налаштування Файлового Менеджера", "FILE_MANAGER.SETTINGS.DESCRIPTION": "Налаштуйте своє робоче середовище для кращого керування файлами та навігації між ними. Налаштуйте відображення елементів, змініть розміри значків та оптимізуйте інтервали відповідно до розміру екрана.", @@ -53,6 +54,7 @@ "FILE_MANAGER.DRIVE.ACTION.BACK": "Назад", "FILE_MANAGER.DRIVE.ACTION.CROP": "Обрізати", "FILE_MANAGER.DRIVE.ACTION.RESIZE": "Змінити розмір", + "FILE_MANAGER.DRIVE.ACTION.MAP": "Розмітити", "FILE_MANAGER.DRIVE.ACTION.CANCEL": "Відмінити", "FILE_MANAGER.DRIVE.ACTION.CREATE": "Створити", "FILE_MANAGER.DRIVE.ACTION.SUBMIT": "Підтвердити", @@ -124,5 +126,21 @@ "FILE_MANAGER.FILE_DETAILS.SIZE": "Розмір", "FILE_MANAGER.FILE_DETAILS.FILE_NAME": "Назва", "FILE_MANAGER.FILE_DETAILS.LAST_MODIFIED": "Змінено", - "FILE_MANAGER.FILE_DETAILS.URL": "URL" + "FILE_MANAGER.FILE_DETAILS.URL": "URL", + + "FILE_MANAGER.IMAGE_MAP.TITLE": "Розмітка зображень", + "FILE_MANAGER.IMAGE_MAP.AREAS.TITLE": "Області", + "FILE_MANAGER.IMAGE_MAP.AREAS.ITEM": "Область", + "FILE_MANAGER.IMAGE_MAP.AREAS.ADD": "Додати область", + "FILE_MANAGER.IMAGE_MAP.AREAS.REMOVE": "Видалити область", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.TITLE": "Вибрана область", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.SHAPE": "Форма", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.URL": "URL", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.TITLE_FIELD": "Назва", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.TITLE_PLACEHOLDER": "Назва області", + "FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.TARGET": "target", + "FILE_MANAGER.IMAGE_MAP.CODE_PREVIEW.TITLE": "Попередній перегляд коду", + "FILE_MANAGER.IMAGE_MAP.SHAPE.RECTANGLE": "Прямокутник", + "FILE_MANAGER.IMAGE_MAP.SHAPE.CIRCLE": "Коло", + "FILE_MANAGER.IMAGE_MAP.SHAPE.POLYGON": "Полігон" } diff --git a/apps/admin/src/core/FileManager/pages/DriveViewerPage/PageLayout.tsx b/apps/admin/src/core/FileManager/pages/DriveViewerPage/PageLayout.tsx index ed704dc..340f1fc 100644 --- a/apps/admin/src/core/FileManager/pages/DriveViewerPage/PageLayout.tsx +++ b/apps/admin/src/core/FileManager/pages/DriveViewerPage/PageLayout.tsx @@ -1,8 +1,8 @@ -import { Crop, Scaling } from 'lucide-react'; +import { Crop, MousePointerSquareDashed, Scaling } from 'lucide-react'; import React from 'react'; import { useIntl } from 'react-intl'; import { Link } from 'react-router-dom'; -import { driveImageEditorPath } from '#core/FileManager/shared/routing/driveLinks'; +import { driveImageEditorPath, driveImageMapPath } from '#core/FileManager/shared/routing/driveLinks'; import BackButton from '#core/FileManager/view/ui/BackButton'; import { Button } from '#shared/ui/Button'; import Breadcrumbs from './Breadcrumbs'; @@ -23,6 +23,12 @@ const PageLayout: React.FC<{ {isFileFormattable(path) && (
+ +
+ + {areas.length > 0 && ( +
+ {areas.map((area, index) => ( +
+
onSelectArea(area.id)} + className={cn( + 'grow cursor-pointer rounded-lg border py-3 px-2 transition', + selectedArea?.id === area.id && 'border-primary bg-primary/5' + )} + > +
+

+ {area.title || + `${intl.formatMessage({ + id: 'FILE_MANAGER.IMAGE_MAP.AREAS.ITEM' + })} ${index + 1}`} +

+ + {area.shape && ( + + {intl.formatMessage({ + id: shapeOptions.find((opt) => opt.value === area.shape)?.labelId + })} + + )} +
+
+ + +
+ ))} +
+ )} + + + {selectedArea && ( +
+
+ +
+ {intl.formatMessage({ + id: 'FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.TITLE' + })} +
+
+ +
+ + + { + onUpdateArea( + (area) => + ({ + ...area, + shape: value, + points: [] + }) as ImageMapArea + ); + }} + className="flex flex-wrap gap-4 items-center" + > + {shapeOptions.map((option) => ( + + ))} + +
+ +
+ + + onUpdateArea((area) => ({ + ...area, + href: e.target.value + })) + } + placeholder="https://example.com" + /> +
+ +
+ + + onUpdateArea((area) => ({ + ...area, + title: e.target.value + })) + } + placeholder={intl.formatMessage({ + id: 'FILE_MANAGER.IMAGE_MAP.SELECTED_AREA.TITLE_PLACEHOLDER' + })} + /> +
+ +
+ + + +
+
+ )} + + {areas.length > 0 && ( +
+
+
+ +
+ {intl.formatMessage({ + id: 'FILE_MANAGER.IMAGE_MAP.CODE_PREVIEW.TITLE' + })} +
+
+ +
+ +