diff --git a/docs/migration-state.md b/docs/migration-state.md index b156babd0..878afc1d0 100644 --- a/docs/migration-state.md +++ b/docs/migration-state.md @@ -4,11 +4,11 @@ Tracks progress of the shared UI migration. Updated by the `/migrate` skill afte ## Current Phase -store +resources ## Current Step -16 +17 ## Step Log @@ -31,7 +31,7 @@ store | 14 | store | Data state slices (Project, File, Library, Console, Shared) | done | 2026-03-10 | | 15 | store | Visual editor slices (FBDFlow, LadderFlow) | done | 2026-03-11 | | 16 | store | Platform state slices (Device, History, web-only) | done | 2026-03-11 | -| 17 | resources | Copy shared resources (styles, assets, locales, declarations) to src2/ | pending | | +| 17 | resources | Copy shared resources (styles, assets, locales, declarations) to src2/ | done | 2026-03-11 | | 18 | components | Atoms batch 1 — shared identical components | pending | | | 19 | components | Atoms batch 2 — divergent components (reconcile) | pending | | | 20 | components | Molecules batch 1 — shared identical | pending | | diff --git a/jest.config.src2.json b/jest.config.src2.json index 4dc0b25a6..716cb4a87 100644 --- a/jest.config.src2.json +++ b/jest.config.src2.json @@ -35,7 +35,9 @@ "!src2/providers/platform/ports/*.ts", "!src2/providers/platform/types.ts", "!src2/adapters/**", - "!src2/renderer/**" + "!src2/renderer/**", + "!src2/locales/**", + "!src2/shared/**" ], "coverageDirectory": "coverage/src2", "coverageReporters": ["text", "text-summary", "lcov", "json-summary"], diff --git a/src2/globals.d.ts b/src2/globals.d.ts new file mode 100644 index 000000000..3390eaa0c --- /dev/null +++ b/src2/globals.d.ts @@ -0,0 +1,16 @@ +/** + * Global constants injected by webpack DefinePlugin at build time + */ + +/** + * Application version from package.json + * @example "4.1.1" + */ +declare const APP_VERSION: string + +/** + * Build date in YYYY-MM-DD format + * Set by CI during release builds, or current date during development + * @example "2026-01-26" + */ +declare const BUILD_DATE: string diff --git a/src2/i18next.d.ts b/src2/i18next.d.ts new file mode 100644 index 000000000..7ab3d3e88 --- /dev/null +++ b/src2/i18next.d.ts @@ -0,0 +1,8 @@ +import { defaultNS, resources } from './locales/i18n' + +declare module 'i18next' { + interface CustomTypeOptions { + defaultNS: typeof defaultNS + resources: (typeof resources)['en'] + } +} diff --git a/src2/locales/en/controls.json b/src2/locales/en/controls.json new file mode 100644 index 000000000..7baaf9325 --- /dev/null +++ b/src2/locales/en/controls.json @@ -0,0 +1,8 @@ +{ + "undo": "Undo", + "redo": "Redo", + "zoomIn": "Zoom In", + "zoomOut": "Zoom Out", + "fitView": "Fit View", + "toggleInteractivity": "Toggle Interactivity" +} diff --git a/src2/locales/en/createPOU.json b/src2/locales/en/createPOU.json new file mode 100644 index 000000000..d366e315e --- /dev/null +++ b/src2/locales/en/createPOU.json @@ -0,0 +1,13 @@ +{ + "title": "Create a new POU", + "errors": { + "name": "The POU name is required", + "type": "The POU type is required", + "language": "The language is required" + }, + "labels": { + "name": "POU Name", + "type": "POU Type", + "language": "Language" + } +} diff --git a/src2/locales/en/createProject.json b/src2/locales/en/createProject.json new file mode 100644 index 000000000..cfaf02848 --- /dev/null +++ b/src2/locales/en/createProject.json @@ -0,0 +1,15 @@ +{ + "dialog": { + "title": "Choose an empty directory for new project" + }, + "errors": { + "directoryNotEmpty": { + "title": "Directory is not empty", + "description": "Chosen folder isn't empty. You can't use it for a new project!" + }, + "failedToCreateFile": { + "title": "Failed to create file", + "description": "Unable to create new project files" + } + } +} diff --git a/src2/locales/en/editorTools.json b/src2/locales/en/editorTools.json new file mode 100644 index 000000000..a00020d38 --- /dev/null +++ b/src2/locales/en/editorTools.json @@ -0,0 +1,9 @@ +{ + "comment": { + "tooltip": "Create a new comment", + "label": "Comment" + }, + "powerRail": "Create a new power rail", + "coil": "Create a coil", + "var": "VAR" +} diff --git a/src2/locales/en/getProject.json b/src2/locales/en/getProject.json new file mode 100644 index 000000000..66c7cd596 --- /dev/null +++ b/src2/locales/en/getProject.json @@ -0,0 +1,8 @@ +{ + "errors": { + "readFile": { + "title": "Failed to read file!", + "description": "Could not read the file: {{filePath}}" + } + } +} diff --git a/src2/locales/en/index.ts b/src2/locales/en/index.ts new file mode 100644 index 000000000..7afd64278 --- /dev/null +++ b/src2/locales/en/index.ts @@ -0,0 +1,16 @@ +export { default as controls } from './controls.json' +export { default as createPOU } from './createPOU.json' +export { default as createProject } from './createProject.json' +export { default as editorTools } from './editorTools.json' +export { default as getProject } from './getProject.json' +export { default as menu } from './menu.json' +export { default as navigation } from './navigation.json' +export { default as openProject } from './openProject.json' +export { default as powerRail } from './powerRail.json' +export { default as powerRailProperties } from './powerRailProperties.json' +export { default as projectServiceResponses } from './projectServiceResponses.json' +export { default as saveProject } from './saveProject.json' +export { default as settings } from './settings.json' +export { default as tools } from './tools.json' +export { default as translation } from './translation.json' +export { default as variables } from './variables.json' diff --git a/src2/locales/en/menu.json b/src2/locales/en/menu.json new file mode 100644 index 000000000..08fda56ab --- /dev/null +++ b/src2/locales/en/menu.json @@ -0,0 +1,82 @@ +{ + "file": { + "label": "File", + "submenu": { + "newProject": "New Project", + "openProject": "Open Project", + "examples": { + "label": "Tutorials and examples", + "submenu": { + "arduino": "1: Arduino_Cloud", + "blink": "2: Blink", + "blinkP1AM": "3: Blink_P1AM", + "multiLanguage": "4: Multi_Language", + "randomGeneratorPragma": "5: Random_Generator_Pragma", + "tcpSocket": "6: TCP_Socket", + "trafficLightFBD": "7: Traffic_Light_FBD" + } + }, + "save": "Save File", + "saveProject": "Save Project", + "saveAs": "Save As", + "closeTab": "Close Tab", + "closeProject": "Close Project", + "exportToPLCOpenXml": "Export to PLCOpen XML", + "exportToCodesysXml": "Export to CODESYS XML", + "pageSetup": "Page Setup", + "preview": "Preview", + "print": "Print", + "updates": "Check for Updates", + "quit": "Quit" + } + }, + "edit": { + "label": "Edit", + "submenu": { + "undo": "Undo", + "redo": "Redo", + "cut": "Cut", + "copy": "Copy", + "paste": "Paste", + "find": "Find", + "findNext": "Find Next", + "findPrevious": "Find Previous", + "findInProject": "Find in Project", + "addElement": { + "label": "Add Element", + "submenu": { + "function": "Function", + "functionBlock": "Function block", + "program": "Program", + "dataType": "Data type", + "cExtension": "C Extension" + } + }, + "selectAll": "Select all", + "delete": "Delete", + "deletePou": "Delete Pou/Datatype" + } + }, + "display": { + "label": "Display", + "submenu": { + "refresh": "Refresh", + "clearErrors": "Clear Errors", + "zoomIn": "Zoom In", + "zoomOut": "Zoom Out", + "switchPerspective": "Switch Perspective", + "fullScreen": "Full Screen", + "resetPerspective": "Reset Perspective", + "sortAlpha": "Sort Alpha", + "theme": "Change Theme" + } + }, + "help": { + "label": "Help", + "submenu": { + "communitySupport": "Community support", + "about": "About" + } + }, + "recent": "Recent" +} diff --git a/src2/locales/en/navigation.json b/src2/locales/en/navigation.json new file mode 100644 index 000000000..81d9baae5 --- /dev/null +++ b/src2/locales/en/navigation.json @@ -0,0 +1,11 @@ +{ + "project": "Project", + "tools": "Tools", + "settings": "Settings", + "editorTools": "Editor Tools", + "variables": "Variables", + "search": "Search", + "filesAndFolders": "Files and Folders", + "transfer": "Transfer", + "zoomInOut": "Zoom" +} diff --git a/src2/locales/en/openProject.json b/src2/locales/en/openProject.json new file mode 100644 index 000000000..18abc5fb6 --- /dev/null +++ b/src2/locales/en/openProject.json @@ -0,0 +1,15 @@ +{ + "dialog": { + "title": "Select a PLC project to open" + }, + "errors": { + "failedToOpenFile": { + "title": "Failed to open file", + "description": "Unable to open project files" + }, + "readFile": { + "title": "Failed to read file!", + "description": "Could not read the file: {{filePath}}" + } + } +} diff --git a/src2/locales/en/powerRail.json b/src2/locales/en/powerRail.json new file mode 100644 index 000000000..cde6344af --- /dev/null +++ b/src2/locales/en/powerRail.json @@ -0,0 +1,3 @@ +{ + "addPin": "Add new pin" +} diff --git a/src2/locales/en/powerRailProperties.json b/src2/locales/en/powerRailProperties.json new file mode 100644 index 000000000..7b7f6efea --- /dev/null +++ b/src2/locales/en/powerRailProperties.json @@ -0,0 +1,7 @@ +{ + "type": "Type", + "left": "Left Power Rail", + "right": "Right Power Rail", + "pinNumber": "Pin number", + "preview": "Preview" +} diff --git a/src2/locales/en/projectServiceResponses.json b/src2/locales/en/projectServiceResponses.json new file mode 100644 index 000000000..08cc9efb9 --- /dev/null +++ b/src2/locales/en/projectServiceResponses.json @@ -0,0 +1,87 @@ +{ + "createProject": { + "success": { + "created": { + "status": 201, + "title": "Project created", + "description": "The project was created successfully! \nYou can now add a POU to your project to start working in OpenPLC Editor" + } + }, + "errors": { + "canceled": { + "status": 400, + "title": "Operation canceled", + "description": "Operation canceled by the user." + }, + "directoryNotEmpty": { + "status": 409, + "title": "Directory is not empty", + "description": "The folder chosen isn't empty. You can't use it for a new project!" + }, + "internalError": { + "status": 500, + "title": "Failed to create file", + "description": "Unable to create new project files" + } + } + }, + "openProject": { + "success": { + "status": 200, + "title": "Success to open file", + "description": "Your project was opened successfully" + }, + "errors": { + "canceled": { + "status": 400, + "title": "Operation canceled", + "description": "Operation canceled by the user." + }, + "readFile": { + "status": 500, + "title": "Failed to read file!", + "description": "Could not read the file." + }, + "readProject": { + "status": 500, + "title": "Failed to read project", + "description": "Could not read the project. Please check the project directory." + }, + "directoryNotFound": { + "status": 404, + "title": "Directory not found", + "description": "The selected directory does not exist." + }, + "invalidProjectDirectory": { + "status": 500, + "title": "Invalid project directory", + "description": "The selected directory is not a valid OpenPLC project directory." + }, + "invalidProject": { + "status": 500, + "title": "Invalid project", + "description": "The selected project is not a valid OpenPLC project." + } + } + }, + "saveProject": { + "success": { + "successToSaveFile": { + "status": 200, + "message": "Your project was saved successfully" + } + }, + "errors": { + "failedToSaveFile": { + "status": 500, + "title": "Failed to save file", + "description": "Unable to save project" + }, + "missingParams": { + "status": 409, + "title": "Missing parameters", + "description": "Missing parameters" + } + } + } +} diff --git a/src2/locales/en/saveProject.json b/src2/locales/en/saveProject.json new file mode 100644 index 000000000..aaccaff89 --- /dev/null +++ b/src2/locales/en/saveProject.json @@ -0,0 +1,14 @@ +{ + "errors": { + "failedToSaveFile": { + "title": "Failed to save file", + "description": "Unable to save project" + } + }, + "success": { + "successToSaveFile": { + "title": "Success to save file", + "description": "Your project was saved successfully" + } + } +} diff --git a/src2/locales/en/settings.json b/src2/locales/en/settings.json new file mode 100644 index 000000000..78e3e3288 --- /dev/null +++ b/src2/locales/en/settings.json @@ -0,0 +1,7 @@ +{ + "theme": { + "tabName": "Theme", + "light": "Light", + "dark": "Dark" + } +} diff --git a/src2/locales/en/tools.json b/src2/locales/en/tools.json new file mode 100644 index 000000000..77426defa --- /dev/null +++ b/src2/locales/en/tools.json @@ -0,0 +1,37 @@ +{ + "common": { + "close": "Close", + "tabName": "Tools" + }, + "menuToolbar": { + "title": "Menu Toolbar", + "new": "New", + "open": "Open", + "save": "Save", + "saveAs": "Save as...", + "print": "Print", + "undo": "Undo", + "redo": "Redo", + "cut": "Cut", + "copy": "Copy", + "paste": "Paste", + "search": "Search in project", + "fullScreen": "Toggle full screen mode", + "toggleTheme": "Toggle dark or light theme" + }, + "statusToolbar": { + "title": "Status Toolbar", + "startSimulation": "Start PLC Simulation", + "generateProgram": "Generate program for Open PLC Runtime", + "transferProgram": "Transfer Program to PLC" + }, + "editorToolbar": { + "title": "Editor Toolbar", + "select": "Select an object", + "move": "Move the view", + "comment": "Create a new comment", + "variable": "Create a new variable", + "block": "Create a new block", + "connection": "Create a new connection" + } +} diff --git a/src2/locales/en/translation.json b/src2/locales/en/translation.json new file mode 100644 index 000000000..5d02cb5b8 --- /dev/null +++ b/src2/locales/en/translation.json @@ -0,0 +1,7 @@ +{ + "programs": "Programs", + "buttons": { + "cancel": "Cancel", + "ok": "OK" + } +} diff --git a/src2/locales/en/variables.json b/src2/locales/en/variables.json new file mode 100644 index 000000000..8f0f11a3d --- /dev/null +++ b/src2/locales/en/variables.json @@ -0,0 +1,13 @@ +{ + "all": "All", + "interface": "Interface", + "input": "Input", + "output": "Output", + "inOut": "InOut", + "externals": "Externals", + "variables": "Variables", + "local": "Local", + "temp": "Temp", + "description": "Description", + "addVariable": "Add variable" +} diff --git a/src2/locales/i18n.ts b/src2/locales/i18n.ts new file mode 100644 index 000000000..5ac87a42b --- /dev/null +++ b/src2/locales/i18n.ts @@ -0,0 +1,20 @@ +import i18n from 'i18next' +import { initReactI18next } from 'react-i18next' + +import * as en from './en' + +export const defaultNS = 'translation' +export const resources = { en } as const + +void i18n.use(initReactI18next).init({ + lng: 'en', + fallbackLng: 'en', + ns: Object.keys(resources.en), + defaultNS, + resources, + interpolation: { + escapeValue: false, + }, +}) + +export { i18n } diff --git a/src2/renderer/App.tsx b/src2/renderer/App.tsx index 273c5b888..66e9dd2da 100644 --- a/src2/renderer/App.tsx +++ b/src2/renderer/App.tsx @@ -1,6 +1,6 @@ import '@xyflow/react/dist/style.css' import 'tailwindcss/tailwind.css' -import '@process:renderer/styles/globals.css' +import './styles/globals.css' import { PlatformProvider } from '../providers/platform' import { editorPorts } from '../adapters/editor-platform' diff --git a/src2/renderer/assets/folder.png b/src2/renderer/assets/folder.png new file mode 100644 index 000000000..faa2d024a Binary files /dev/null and b/src2/renderer/assets/folder.png differ diff --git a/src2/renderer/assets/icons/Fallback.tsx b/src2/renderer/assets/icons/Fallback.tsx new file mode 100644 index 000000000..d4ea204ae --- /dev/null +++ b/src2/renderer/assets/icons/Fallback.tsx @@ -0,0 +1,59 @@ +import { cn } from '../../../utils/cn' +import { ComponentProps } from 'react' + +type IFallBackIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-4 h-4', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} +export const FallBackIcon = (props: IFallBackIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/Types/iconTypes.tsx b/src2/renderer/assets/icons/Types/iconTypes.tsx new file mode 100644 index 000000000..ef181d0da --- /dev/null +++ b/src2/renderer/assets/icons/Types/iconTypes.tsx @@ -0,0 +1,7 @@ +import { ComponentProps } from 'react' + +export type IIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' + variableAsTable?: boolean + variableAsCode?: boolean +} diff --git a/src2/renderer/assets/icons/about/logo.svg b/src2/renderer/assets/icons/about/logo.svg new file mode 100644 index 000000000..8338941da --- /dev/null +++ b/src2/renderer/assets/icons/about/logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src2/renderer/assets/icons/base/left-arrow.svg b/src2/renderer/assets/icons/base/left-arrow.svg new file mode 100644 index 000000000..894263f21 --- /dev/null +++ b/src2/renderer/assets/icons/base/left-arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src2/renderer/assets/icons/base/right-arrow.svg b/src2/renderer/assets/icons/base/right-arrow.svg new file mode 100644 index 000000000..c3fb91330 --- /dev/null +++ b/src2/renderer/assets/icons/base/right-arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src2/renderer/assets/icons/flow/Coil.tsx b/src2/renderer/assets/icons/flow/Coil.tsx new file mode 100644 index 000000000..9cd2a181f --- /dev/null +++ b/src2/renderer/assets/icons/flow/Coil.tsx @@ -0,0 +1,168 @@ +type CoilSVGProps = { + width?: number + height?: number + parenthesesClassName?: string + parenthesesColor?: string +} + +export const DefaultCoil = ({ width, height, parenthesesClassName, parenthesesColor }: CoilSVGProps) => { + return ( + + + + + ) +} + +export const NegatedCoil = ({ width, height, parenthesesClassName, parenthesesColor }: CoilSVGProps) => { + return ( + + + + + + ) +} + +export const SetCoil = ({ width, height, parenthesesClassName, parenthesesColor }: CoilSVGProps) => { + return ( + + + + + + ) +} + +export const ResetCoil = ({ width, height, parenthesesClassName, parenthesesColor }: CoilSVGProps) => { + return ( + + + + + + ) +} + +export const RisingEdgeCoil = ({ width, height, parenthesesClassName, parenthesesColor }: CoilSVGProps) => { + return ( + + + + + + ) +} + +export const FallingEdgeCoil = ({ width, height, parenthesesClassName, parenthesesColor }: CoilSVGProps) => { + return ( + + + + + + ) +} diff --git a/src2/renderer/assets/icons/flow/Contact.tsx b/src2/renderer/assets/icons/flow/Contact.tsx new file mode 100644 index 000000000..40d993863 --- /dev/null +++ b/src2/renderer/assets/icons/flow/Contact.tsx @@ -0,0 +1,138 @@ +type ContactSVGType = { + width?: number + height?: number + strokeClassName?: string + strokeColor?: string +} + +export const DefaultContact = ({ strokeClassName, strokeColor, width, height }: ContactSVGType) => { + return ( + + + + + ) +} + +export const NegatedContact = ({ strokeClassName, strokeColor, width, height }: ContactSVGType) => { + return ( + + + + + + ) +} + +export const RisingEdgeContact = ({ strokeClassName, strokeColor, width, height }: ContactSVGType) => { + return ( + + + + + + ) +} + +export const FallingEdgeContact = ({ strokeClassName, strokeColor, width, height }: ContactSVGType) => { + return ( + + + + + + ) +} diff --git a/src2/renderer/assets/icons/flow/Placeholder.tsx b/src2/renderer/assets/icons/flow/Placeholder.tsx new file mode 100644 index 000000000..8c24f6976 --- /dev/null +++ b/src2/renderer/assets/icons/flow/Placeholder.tsx @@ -0,0 +1,38 @@ +type PlaceholderSVGType = { + width?: number + height?: number + className?: string +} + +export const PlaceholderNode = ({ width, height, className }: PlaceholderSVGType) => { + return ( + + + + ) +} + +export const PlaceholderNodeFilled = ({ width, height, className }: PlaceholderSVGType) => { + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/index.ts b/src2/renderer/assets/icons/index.ts new file mode 100644 index 000000000..993aa65d2 --- /dev/null +++ b/src2/renderer/assets/icons/index.ts @@ -0,0 +1,84 @@ +/** Reexport all icons from library folder */ +export * from './library/CloseFolder' +export * from './library/File' +export * from './library/OpenFolder' + +/** Reexport all icons from project folder */ +export * from './project/Array' +export * from './project/CExt' +export * from './project/Cpp' +export * from './project/DataType' +export * from './project/Device' +export * from './project/Enum' +export * from './project/FBD' +export * from './project/fbd/Block' +export * from './project/fbd/Connector' +export * from './project/fbd/Continuation' +export * from './project/fbd/VariableIn' +export * from './project/fbd/VariableInOut' +export * from './project/fbd/VariableOut' +export * from './project/Function' +export * from './project/FunctionBlock' +export * from './project/GenericDT' +export * from './project/IL' +export * from './project/ladder/Block' +export * from './project/ladder/Coil' +export * from './project/ladder/Contact' +export * from './project/LD' +export * from './project/Loop' +export * from './project/PLC' +export * from './project/Program' +export * from './project/Python' +export * from './project/RemoteDevice' +export * from './project/Resource' +export * from './project/Server' +export * from './project/SFC' +export * from './project/ST' +export * from './project/Structure' + +/** Reexport all icons from interface folder */ +export * from './Fallback' +export * from './interface/Arrow' +export * from './interface/ArrowUp' +export * from './interface/Book' +export * from './interface/Broom' +export * from './interface/Close' +export * from './interface/Config' +export * from './interface/DarkTheme' +export * from './interface/Debugger' +export * from './interface/DeviceTransfer' +export * from './interface/Download' +export * from './interface/Exit' +export * from './interface/Folder' +export * from './interface/LightTheme' +export * from './interface/Magnifier' +export * from './interface/Minus' +export * from './interface/MoreOptions' +export * from './interface/Path' +export * from './interface/Pause' +export * from './interface/Pencil' +export * from './interface/Play' +export * from './interface/Plus' +export * from './interface/Refresh' +export * from './interface/Search' +export * from './interface/StickArrow' +export * from './interface/Stop' +export * from './interface/Timer' +export * from './interface/Transfer' +export * from './interface/TrashCan' +export * from './interface/Video' +export * from './interface/View' +export * from './interface/ViewHidden' +export * from './interface/Zap' +export * from './interface/ZoomInOut' + +/** Reexport all icons from flow folder */ +export * from './flow/Coil' +export * from './flow/Contact' +export * from './flow/Placeholder' + +/** Reexport all icons from window-controls folder */ +export * from './window-controls/Close' +export * from './window-controls/Exit-Maximize' +export * from './window-controls/Maximize' +export * from './window-controls/Minimize' diff --git a/src2/renderer/assets/icons/interface/Arrow.tsx b/src2/renderer/assets/icons/interface/Arrow.tsx new file mode 100644 index 000000000..7b415bd59 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Arrow.tsx @@ -0,0 +1,57 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithRef, ElementType } from 'react' + +type IArrowIconProps = ComponentPropsWithRef<'svg'> & { + variant?: 'default' | 'primary' | 'secondary' + direction?: 'up' | 'down' | 'left' | 'right' + size?: 'sm' | 'md' | 'lg' +} + +const directionClasses = { + left: 'rotate-0', + up: 'rotate-90', + right: 'rotate-180', + down: 'rotate-270', +} + +const variantClasses = { + default: 'stroke-brand-light', + primary: 'stroke-brand', + secondary: 'stroke-brand-medium-dark', +} + +const sizeClasses = { + sm: 'w-4 h-4', + md: 'w-6 h-6', + lg: 'w-8 h-8', +} + +export const ArrowIcon: ElementType = ({ + className, + variant = 'default', + size = 'sm', + direction = 'left', + ref, + ...res +}) => { + return ( + + Arrow Icon + + + ) +} diff --git a/src2/renderer/assets/icons/interface/ArrowButton.tsx b/src2/renderer/assets/icons/interface/ArrowButton.tsx new file mode 100644 index 000000000..f32ef486f --- /dev/null +++ b/src2/renderer/assets/icons/interface/ArrowButton.tsx @@ -0,0 +1,52 @@ +import { cn } from '../../../../utils/cn' +import React from 'react' +import { ComponentPropsWithRef, ElementType } from 'react' + +type IArrowButtonIconProps = ComponentPropsWithRef<'svg'> & { + variant?: 'default' | 'primary' | 'secondary' + direction?: 'up' | 'down' | 'left' | 'right' + size?: 'sm' | 'md' | 'lg' +} + +const directionClasses = { + up: 'rotate-0', + left: 'rotate-90', + down: 'rotate-180', + right: 'rotate-270', +} + +const variantClasses = { + default: 'stroke-brand-light', + primary: 'stroke-brand', + secondary: 'stroke-brand-medium-dark', +} + +const sizeClasses = { + sm: 'w-3 h-3', + md: 'w-5 h-5', + lg: 'w-7 h-7', +} +const ArrowButton: ElementType = ({ + className, + variant = 'default', + size = 'sm', + direction = 'left', + ref, + ...res +}) => { + return ( + + + + ) +} + +export default ArrowButton diff --git a/src2/renderer/assets/icons/interface/ArrowUp.tsx b/src2/renderer/assets/icons/interface/ArrowUp.tsx new file mode 100644 index 000000000..1858fa644 --- /dev/null +++ b/src2/renderer/assets/icons/interface/ArrowUp.tsx @@ -0,0 +1,33 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IArrowUpIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} + +export const ArrowUp = (props: IArrowUpIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Book.tsx b/src2/renderer/assets/icons/interface/Book.tsx new file mode 100644 index 000000000..38a68bce5 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Book.tsx @@ -0,0 +1,35 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IBookIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} +export const BookIcon = (props: IBookIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Broom.tsx b/src2/renderer/assets/icons/interface/Broom.tsx new file mode 100644 index 000000000..26491a9c5 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Broom.tsx @@ -0,0 +1,22 @@ +import { ComponentPropsWithRef } from 'react' + +type BroomIconProps = ComponentPropsWithRef<'svg'> + +const BroomIcon = (props: BroomIconProps) => ( + + + +) +export { BroomIcon } diff --git a/src2/renderer/assets/icons/interface/Close.tsx b/src2/renderer/assets/icons/interface/Close.tsx new file mode 100644 index 000000000..2246541f7 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Close.tsx @@ -0,0 +1,34 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +const CloseIcon = (props: ComponentPropsWithoutRef<'svg'>) => { + const { className, ...rest } = props + return ( + + Close Icon + + + ) +} + +const CloseFilledIcon = ({ className, ...rest }: ComponentPropsWithoutRef<'svg'>) => { + return ( + + + + + ) +} + +export { CloseFilledIcon, CloseIcon } diff --git a/src2/renderer/assets/icons/interface/CodeIcon.tsx b/src2/renderer/assets/icons/interface/CodeIcon.tsx new file mode 100644 index 000000000..a2a6c952f --- /dev/null +++ b/src2/renderer/assets/icons/interface/CodeIcon.tsx @@ -0,0 +1,33 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' + currentVisible?: boolean +} + +export const CodeIcon = (props: IProps) => { + const { currentVisible, className, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.medium[size] + + return ( + + Code Icon + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Comment.tsx b/src2/renderer/assets/icons/interface/Comment.tsx new file mode 100644 index 000000000..1e2f8fcb6 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Comment.tsx @@ -0,0 +1,24 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +const CommentIcon = (props: ComponentPropsWithoutRef<'svg'>) => { + const { className, ...rest } = props + return ( + + Comment Icon + + + + ) +} + +export { CommentIcon } diff --git a/src2/renderer/assets/icons/interface/Config.tsx b/src2/renderer/assets/icons/interface/Config.tsx new file mode 100644 index 000000000..8dfa804fc --- /dev/null +++ b/src2/renderer/assets/icons/interface/Config.tsx @@ -0,0 +1,42 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IConfigIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} +export const ConfigIcon = (props: IConfigIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/DarkTheme.tsx b/src2/renderer/assets/icons/interface/DarkTheme.tsx new file mode 100644 index 000000000..1f3957c8f --- /dev/null +++ b/src2/renderer/assets/icons/interface/DarkTheme.tsx @@ -0,0 +1,68 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export const DarkThemeIcon = (props: IIconProps) => { + const { className, size = 'md', ...res } = props + const sizeClasses = IconStyles.sizeClasses.medium[size] + return ( + + Dark Theme Icon + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Debugger.tsx b/src2/renderer/assets/icons/interface/Debugger.tsx new file mode 100644 index 000000000..f6e5bf83c --- /dev/null +++ b/src2/renderer/assets/icons/interface/Debugger.tsx @@ -0,0 +1,54 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IDebuggerIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' + variant?: 'default' | 'muted' +} + +const SizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} +const VariantClasses = { + default: '#0464FB', + muted: '#B4D0FE', +} + +export const DebuggerIcon = ({ className, variant = 'default', size = 'sm', ...res }: IDebuggerIconProps) => { + return ( + + Debugger Icon + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/DeviceTransfer.tsx b/src2/renderer/assets/icons/interface/DeviceTransfer.tsx new file mode 100644 index 000000000..01a517e16 --- /dev/null +++ b/src2/renderer/assets/icons/interface/DeviceTransfer.tsx @@ -0,0 +1,49 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IDeviceTransferIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} +export const DeviceTransferIcon = (props: IDeviceTransferIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Download.tsx b/src2/renderer/assets/icons/interface/Download.tsx new file mode 100644 index 000000000..9d838f762 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Download.tsx @@ -0,0 +1,30 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export const DownloadIcon = (props: IIconProps) => { + const { className, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + return ( + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/DragHandle.tsx b/src2/renderer/assets/icons/interface/DragHandle.tsx new file mode 100644 index 000000000..679d246c3 --- /dev/null +++ b/src2/renderer/assets/icons/interface/DragHandle.tsx @@ -0,0 +1,23 @@ +export const DragHandleIcon = (props: React.SVGProps) => { + return ( + + drag-handle-line + + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Duplicate.tsx b/src2/renderer/assets/icons/interface/Duplicate.tsx new file mode 100644 index 000000000..808c92980 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Duplicate.tsx @@ -0,0 +1,21 @@ +import { IconStyles } from '../../../data' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export const DuplicateIcon = (props: IIconProps) => { + const { className, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + + return ( + + + duplicate icon + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/EditButton.tsx b/src2/renderer/assets/icons/interface/EditButton.tsx new file mode 100644 index 000000000..72f7684fa --- /dev/null +++ b/src2/renderer/assets/icons/interface/EditButton.tsx @@ -0,0 +1,58 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithRef, forwardRef } from 'react' + +type IEditButtonIconProps = ComponentPropsWithRef<'svg'> & { + variant?: 'default' | 'primary' | 'secondary' + direction?: 'up' | 'down' | 'left' | 'right' + size?: 'sm' | 'md' | 'lg' +} + +const directionClasses = { + up: 'rotate-0', + left: 'rotate-90', + down: 'rotate-180', + right: 'rotate-270', +} + +const variantClasses = { + default: 'stroke-brand-light', + primary: 'stroke-brand', + secondary: 'stroke-brand-medium-dark', +} + +const sizeClasses = { + sm: 'w-3 h-3', + md: 'w-5 h-5', + lg: 'w-7 h-7', +} +const EditButton = forwardRef( + ({ className, variant = 'default', size = 'sm', direction = 'up', ...res }, ref) => { + return ( + + + + + ) + }, +) + +export default EditButton diff --git a/src2/renderer/assets/icons/interface/Exit.tsx b/src2/renderer/assets/icons/interface/Exit.tsx new file mode 100644 index 000000000..eabe4ac1a --- /dev/null +++ b/src2/renderer/assets/icons/interface/Exit.tsx @@ -0,0 +1,27 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export const ExitIcon = (props: IIconProps) => { + const { className, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Folder.tsx b/src2/renderer/assets/icons/interface/Folder.tsx new file mode 100644 index 000000000..12f3ad996 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Folder.tsx @@ -0,0 +1,34 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' +type IFolderIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} +export const FolderIcon = (props: IFolderIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/LightTheme.tsx b/src2/renderer/assets/icons/interface/LightTheme.tsx new file mode 100644 index 000000000..d52ce1172 --- /dev/null +++ b/src2/renderer/assets/icons/interface/LightTheme.tsx @@ -0,0 +1,104 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export const LightThemeIcon = (props: IIconProps) => { + const { className, size = 'md', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Magnifier.tsx b/src2/renderer/assets/icons/interface/Magnifier.tsx new file mode 100644 index 000000000..ec8b72b78 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Magnifier.tsx @@ -0,0 +1,33 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IMagnifierIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} + +export const MagnifierIcon = (props: IMagnifierIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Minus.tsx b/src2/renderer/assets/icons/interface/Minus.tsx new file mode 100644 index 000000000..a506a68f1 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Minus.tsx @@ -0,0 +1,28 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IMinusIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} + +export const MinusIcon = (props: IMinusIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + Minus Icon + + + ) +} diff --git a/src2/renderer/assets/icons/interface/MoreOptions.tsx b/src2/renderer/assets/icons/interface/MoreOptions.tsx new file mode 100644 index 000000000..fcb84ab58 --- /dev/null +++ b/src2/renderer/assets/icons/interface/MoreOptions.tsx @@ -0,0 +1,20 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +const MoreOptionsIcon = ({ className, ...rest }: ComponentPropsWithoutRef<'svg'>) => { + return ( + + + + + + ) +} + +export { MoreOptionsIcon } diff --git a/src2/renderer/assets/icons/interface/Next.tsx b/src2/renderer/assets/icons/interface/Next.tsx new file mode 100644 index 000000000..58bdc59e0 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Next.tsx @@ -0,0 +1,30 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export default function NextIcon(props: IIconProps) { + const { className, fill, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + return ( + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Path.tsx b/src2/renderer/assets/icons/interface/Path.tsx new file mode 100644 index 000000000..42909e93a --- /dev/null +++ b/src2/renderer/assets/icons/interface/Path.tsx @@ -0,0 +1,30 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IFBDIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const PathIcon = (props: IFBDIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Pause.tsx b/src2/renderer/assets/icons/interface/Pause.tsx new file mode 100644 index 000000000..6a0acf10e --- /dev/null +++ b/src2/renderer/assets/icons/interface/Pause.tsx @@ -0,0 +1,27 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export const PauseIcon = (props: IIconProps) => { + const { className, fill, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + return ( + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Pencil.tsx b/src2/renderer/assets/icons/interface/Pencil.tsx new file mode 100644 index 000000000..571e1c91a --- /dev/null +++ b/src2/renderer/assets/icons/interface/Pencil.tsx @@ -0,0 +1,33 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IPencilIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const PencilIcon = (props: IPencilIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + Pencil Icon + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Play.tsx b/src2/renderer/assets/icons/interface/Play.tsx new file mode 100644 index 000000000..720b4ff9c --- /dev/null +++ b/src2/renderer/assets/icons/interface/Play.tsx @@ -0,0 +1,20 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export const PlayIcon = (props: IIconProps) => { + const { className, fill, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Plus.tsx b/src2/renderer/assets/icons/interface/Plus.tsx new file mode 100644 index 000000000..139861cf0 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Plus.tsx @@ -0,0 +1,28 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IPlusIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} + +export const PlusIcon = (props: IPlusIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + Plus Icon + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Prohibited.tsx b/src2/renderer/assets/icons/interface/Prohibited.tsx new file mode 100644 index 000000000..6ea0d4747 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Prohibited.tsx @@ -0,0 +1,26 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type ProhibitedProps = ComponentPropsWithoutRef<'svg'> + +export const ProhibitedIcon = (props: ProhibitedProps) => { + const { className, ...res } = props + + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Recent.tsx b/src2/renderer/assets/icons/interface/Recent.tsx new file mode 100644 index 000000000..0fd8dee7a --- /dev/null +++ b/src2/renderer/assets/icons/interface/Recent.tsx @@ -0,0 +1,30 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IRecentIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} +export default function RecentProjectIcon(props: IRecentIconProps) { + const { className, size = 'sm', ...res } = props + return ( + + Recent Icon + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Refresh.tsx b/src2/renderer/assets/icons/interface/Refresh.tsx new file mode 100644 index 000000000..b62c85d99 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Refresh.tsx @@ -0,0 +1,27 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type RefreshIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-4 h-4', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} +const RefreshIcon = ({ className, size = 'sm', ...res }: RefreshIconProps) => { + return ( + + + + ) +} + +export { RefreshIcon } diff --git a/src2/renderer/assets/icons/interface/Search.tsx b/src2/renderer/assets/icons/interface/Search.tsx new file mode 100644 index 000000000..3a92f6966 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Search.tsx @@ -0,0 +1,27 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export const SearchIcon = (props: IIconProps) => { + const { className, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + + return ( + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/StickArrow.tsx b/src2/renderer/assets/icons/interface/StickArrow.tsx new file mode 100644 index 000000000..0ab9d2a52 --- /dev/null +++ b/src2/renderer/assets/icons/interface/StickArrow.tsx @@ -0,0 +1,42 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IStickArrowIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' + direction?: 'up' | 'down' | 'left' | 'right' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} + +const directionClasses = { + up: 'rotate-270', + down: 'rotate-90', + left: 'rotate-180', + right: 'rotate-0', +} + +export const StickArrowIcon = (props: IStickArrowIconProps) => { + const { className, size = 'sm', direction = 'up', ...res } = props + return ( + + Stick Arrow Icon + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Stop.tsx b/src2/renderer/assets/icons/interface/Stop.tsx new file mode 100644 index 000000000..325c1a1cd --- /dev/null +++ b/src2/renderer/assets/icons/interface/Stop.tsx @@ -0,0 +1,20 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export const StopIcon = (props: IIconProps) => { + const { className, fill, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/TableIcon.tsx b/src2/renderer/assets/icons/interface/TableIcon.tsx new file mode 100644 index 000000000..640f9ff22 --- /dev/null +++ b/src2/renderer/assets/icons/interface/TableIcon.tsx @@ -0,0 +1,34 @@ +import { IconStyles } from '../../../data' +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' + currentVisible?: boolean + backgroundVariant?: 'light' | 'dark' +} + +export const TableIcon = (props: IProps) => { + const { currentVisible, className, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.medium[size] + + return ( + + Table Icon + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Timer.tsx b/src2/renderer/assets/icons/interface/Timer.tsx new file mode 100644 index 000000000..044e0bba2 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Timer.tsx @@ -0,0 +1,30 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IFBDIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const TimerIcon = (props: IFBDIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Transfer.tsx b/src2/renderer/assets/icons/interface/Transfer.tsx new file mode 100644 index 000000000..1bec70f8c --- /dev/null +++ b/src2/renderer/assets/icons/interface/Transfer.tsx @@ -0,0 +1,36 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export const TransferIcon = (props: IIconProps) => { + const { className, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + return ( + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/TrashCan.tsx b/src2/renderer/assets/icons/interface/TrashCan.tsx new file mode 100644 index 000000000..dedc9794a --- /dev/null +++ b/src2/renderer/assets/icons/interface/TrashCan.tsx @@ -0,0 +1,25 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type TrashCanProps = ComponentPropsWithoutRef<'svg'> + +export const TrashCanIcon = (props: TrashCanProps) => { + const { className, ...res } = props + return ( + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Video.tsx b/src2/renderer/assets/icons/interface/Video.tsx new file mode 100644 index 000000000..7583c7484 --- /dev/null +++ b/src2/renderer/assets/icons/interface/Video.tsx @@ -0,0 +1,38 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IVideoIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} +export const VideoIcon = (props: IVideoIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/View.tsx b/src2/renderer/assets/icons/interface/View.tsx new file mode 100644 index 000000000..2ccfacd83 --- /dev/null +++ b/src2/renderer/assets/icons/interface/View.tsx @@ -0,0 +1,26 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export default function ViewIcon(props: IIconProps) { + const { stroke, className, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/ViewHidden.tsx b/src2/renderer/assets/icons/interface/ViewHidden.tsx new file mode 100644 index 000000000..ce9c34fd8 --- /dev/null +++ b/src2/renderer/assets/icons/interface/ViewHidden.tsx @@ -0,0 +1,29 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export default function ViewHiddenIcon(props: IIconProps) { + const { stroke, className, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + + return ( + + {/* Eye shape */} + + {/* Diagonal line through the eye */} + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Warning.tsx b/src2/renderer/assets/icons/interface/Warning.tsx new file mode 100644 index 000000000..43a46683c --- /dev/null +++ b/src2/renderer/assets/icons/interface/Warning.tsx @@ -0,0 +1,48 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithRef, ElementType } from 'react' + +type IWarningIconProps = ComponentPropsWithRef<'svg'> & { + variant?: 'default' | 'primary' | 'secondary' + direction?: 'up' | 'down' | 'left' | 'right' + size?: 'sm' | 'md' | 'lg' +} + +const variantClasses = { + default: 'stroke-brand-light', + primary: 'stroke-brand', + secondary: 'stroke-brand-medium-dark', +} + +const sizeClasses = { + sm: 'w-4 h-4', + md: 'w-6 h-6', + lg: 'w-8 h-8', +} + +export const WarningIcon: ElementType = ({ + className, + variant = 'default', + size = 'sm', + ref, + ...res +}) => { + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/Zap.tsx b/src2/renderer/assets/icons/interface/Zap.tsx new file mode 100644 index 000000000..6e3df7f0c --- /dev/null +++ b/src2/renderer/assets/icons/interface/Zap.tsx @@ -0,0 +1,23 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export default function ZapIcon(props: IIconProps) { + const { className, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + return ( + + + + ) +} diff --git a/src2/renderer/assets/icons/interface/ZoomInOut.tsx b/src2/renderer/assets/icons/interface/ZoomInOut.tsx new file mode 100644 index 000000000..d1a732abb --- /dev/null +++ b/src2/renderer/assets/icons/interface/ZoomInOut.tsx @@ -0,0 +1,30 @@ +import { IconStyles } from '../../../data/constants/icon-styles' +import { cn } from '../../../../utils/cn' + +import { IIconProps } from '../Types/iconTypes' + +export const ZoomInOut = (props: IIconProps) => { + const { className, size = 'sm', ...res } = props + const sizeClasses = IconStyles.sizeClasses.small[size] + return ( + + + + + ) +} diff --git a/src2/renderer/assets/icons/library/CloseFolder.tsx b/src2/renderer/assets/icons/library/CloseFolder.tsx new file mode 100644 index 000000000..32c2777c3 --- /dev/null +++ b/src2/renderer/assets/icons/library/CloseFolder.tsx @@ -0,0 +1,37 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type ILibraryCloseFolderIconProps = ComponentProps<'svg'> & { + size: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} + +export const LibraryCloseFolderIcon = (props: ILibraryCloseFolderIconProps) => { + const { size = 'sm', className, ...res } = props + return ( + + + + + ) +} diff --git a/src2/renderer/assets/icons/library/File.tsx b/src2/renderer/assets/icons/library/File.tsx new file mode 100644 index 000000000..b67327d5a --- /dev/null +++ b/src2/renderer/assets/icons/library/File.tsx @@ -0,0 +1,47 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type ILibraryFileIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} + +export const LibraryFileIcon = (props: ILibraryFileIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/library/OpenFolder.tsx b/src2/renderer/assets/icons/library/OpenFolder.tsx new file mode 100644 index 000000000..6d7b3aa87 --- /dev/null +++ b/src2/renderer/assets/icons/library/OpenFolder.tsx @@ -0,0 +1,35 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type ILibraryOpenFolderIconProps = ComponentProps<'svg'> & { + size: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', +} + +export const LibraryOpenFolderIcon = (props: ILibraryOpenFolderIconProps) => { + const { size = 'sm', className, ...res } = props + return ( + + + + + ) +} diff --git a/src2/renderer/assets/icons/oplc.tsx b/src2/renderer/assets/icons/oplc.tsx new file mode 100644 index 000000000..2444f0923 --- /dev/null +++ b/src2/renderer/assets/icons/oplc.tsx @@ -0,0 +1,29 @@ +import { cn } from '../../../utils/cn' +import { ComponentProps } from 'react' + +type IOpenPLCIconProps = ComponentProps<'svg'> + +export const OpenPLCIcon = (props: IOpenPLCIconProps) => { + const { className, ...rest } = props + return ( + + OpenPLC Logo + {/* */} + + + + ) +} diff --git a/src2/renderer/assets/icons/project/Array.tsx b/src2/renderer/assets/icons/project/Array.tsx new file mode 100644 index 000000000..769c3bb94 --- /dev/null +++ b/src2/renderer/assets/icons/project/Array.tsx @@ -0,0 +1,108 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type ArrayIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const ArrayIcon = (props: ArrayIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + Array Icon + + + + + + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/CExt.tsx b/src2/renderer/assets/icons/project/CExt.tsx new file mode 100644 index 000000000..dd4a34610 --- /dev/null +++ b/src2/renderer/assets/icons/project/CExt.tsx @@ -0,0 +1,50 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type ICExtIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const CExtIcon = (props: ICExtIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + CExt Icon + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/Cpp.tsx b/src2/renderer/assets/icons/project/Cpp.tsx new file mode 100644 index 000000000..b21eb77de --- /dev/null +++ b/src2/renderer/assets/icons/project/Cpp.tsx @@ -0,0 +1,39 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type CppIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const CppIcon = (props: CppIconProps) => { + const { className, size = 'sm', ...rest } = props + return ( + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/DataType.tsx b/src2/renderer/assets/icons/project/DataType.tsx new file mode 100644 index 000000000..838e12280 --- /dev/null +++ b/src2/renderer/assets/icons/project/DataType.tsx @@ -0,0 +1,40 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IDataTypeIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const DataTypeIcon = (props: IDataTypeIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + Data Type Icon + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/Device.tsx b/src2/renderer/assets/icons/project/Device.tsx new file mode 100644 index 000000000..8b179c18c --- /dev/null +++ b/src2/renderer/assets/icons/project/Device.tsx @@ -0,0 +1,39 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IDeviceIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const DeviceIcon = (props: IDeviceIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/Enum.tsx b/src2/renderer/assets/icons/project/Enum.tsx new file mode 100644 index 000000000..8b3395e4a --- /dev/null +++ b/src2/renderer/assets/icons/project/Enum.tsx @@ -0,0 +1,82 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type EnumIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const EnumIcon = (props: EnumIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + Enum Icon + + + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/FBD.tsx b/src2/renderer/assets/icons/project/FBD.tsx new file mode 100644 index 000000000..1e24cbf53 --- /dev/null +++ b/src2/renderer/assets/icons/project/FBD.tsx @@ -0,0 +1,47 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IFBDIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const FBDIcon = (props: IFBDIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/Function.tsx b/src2/renderer/assets/icons/project/Function.tsx new file mode 100644 index 000000000..aa37c2101 --- /dev/null +++ b/src2/renderer/assets/icons/project/Function.tsx @@ -0,0 +1,52 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IFunctionIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} +export const FunctionIcon = (props: IFunctionIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + Function Icon + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/FunctionBlock.tsx b/src2/renderer/assets/icons/project/FunctionBlock.tsx new file mode 100644 index 000000000..4116d4691 --- /dev/null +++ b/src2/renderer/assets/icons/project/FunctionBlock.tsx @@ -0,0 +1,46 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IFunctionBlockIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} +export const FunctionBlockIcon = (props: IFunctionBlockIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + Function Block Icon + + + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/GenericDT.tsx b/src2/renderer/assets/icons/project/GenericDT.tsx new file mode 100644 index 000000000..ec04c5895 --- /dev/null +++ b/src2/renderer/assets/icons/project/GenericDT.tsx @@ -0,0 +1,61 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IGenericIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const GenericIcon = (props: IGenericIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + Generic Icon + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/IL.tsx b/src2/renderer/assets/icons/project/IL.tsx new file mode 100644 index 000000000..3e79a826e --- /dev/null +++ b/src2/renderer/assets/icons/project/IL.tsx @@ -0,0 +1,36 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IILIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} +export const ILIcon = (props: IILIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/LD.tsx b/src2/renderer/assets/icons/project/LD.tsx new file mode 100644 index 000000000..6fb27ff37 --- /dev/null +++ b/src2/renderer/assets/icons/project/LD.tsx @@ -0,0 +1,39 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type ILDIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} +export const LDIcon = (props: ILDIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/Loop.tsx b/src2/renderer/assets/icons/project/Loop.tsx new file mode 100644 index 000000000..01b52b004 --- /dev/null +++ b/src2/renderer/assets/icons/project/Loop.tsx @@ -0,0 +1,36 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type ILoopIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} +export default function LoopIcon(props: ILoopIconProps) { + const { className, size = 'sm', ...res } = props + return ( + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/PLC.tsx b/src2/renderer/assets/icons/project/PLC.tsx new file mode 100644 index 000000000..3daae34dc --- /dev/null +++ b/src2/renderer/assets/icons/project/PLC.tsx @@ -0,0 +1,39 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IPLCIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const PLCIcon = (props: IPLCIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/Program.tsx b/src2/renderer/assets/icons/project/Program.tsx new file mode 100644 index 000000000..53d33f76f --- /dev/null +++ b/src2/renderer/assets/icons/project/Program.tsx @@ -0,0 +1,43 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IProgramIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} +export const ProgramIcon = (props: IProgramIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + Program Icon + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/Python.tsx b/src2/renderer/assets/icons/project/Python.tsx new file mode 100644 index 000000000..f7b62e871 --- /dev/null +++ b/src2/renderer/assets/icons/project/Python.tsx @@ -0,0 +1,39 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type PythonIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const PythonIcon = (props: PythonIconProps) => { + const { className, size = 'sm', ...rest } = props + return ( + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/RemoteDevice.tsx b/src2/renderer/assets/icons/project/RemoteDevice.tsx new file mode 100644 index 000000000..22d2fd9f4 --- /dev/null +++ b/src2/renderer/assets/icons/project/RemoteDevice.tsx @@ -0,0 +1,38 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IRemoteDeviceIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const RemoteDeviceIcon = (props: IRemoteDeviceIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/Resource.tsx b/src2/renderer/assets/icons/project/Resource.tsx new file mode 100644 index 000000000..e7281d42a --- /dev/null +++ b/src2/renderer/assets/icons/project/Resource.tsx @@ -0,0 +1,46 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IResourceIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} +export const ResourceIcon = (props: IResourceIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/SFC.tsx b/src2/renderer/assets/icons/project/SFC.tsx new file mode 100644 index 000000000..e4d765e9d --- /dev/null +++ b/src2/renderer/assets/icons/project/SFC.tsx @@ -0,0 +1,47 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type ISFCIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const SFCIcon = (props: ISFCIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/ST.tsx b/src2/renderer/assets/icons/project/ST.tsx new file mode 100644 index 000000000..f4fe87ec7 --- /dev/null +++ b/src2/renderer/assets/icons/project/ST.tsx @@ -0,0 +1,39 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type ISTIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} +export const STIcon = (props: ISTIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/Server.tsx b/src2/renderer/assets/icons/project/Server.tsx new file mode 100644 index 000000000..07c4ef9a6 --- /dev/null +++ b/src2/renderer/assets/icons/project/Server.tsx @@ -0,0 +1,34 @@ +import { cn } from '../../../../utils/cn' +import { ComponentProps } from 'react' + +type IServerIconProps = ComponentProps<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const ServerIcon = (props: IServerIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/Structure.tsx b/src2/renderer/assets/icons/project/Structure.tsx new file mode 100644 index 000000000..0acad2a37 --- /dev/null +++ b/src2/renderer/assets/icons/project/Structure.tsx @@ -0,0 +1,57 @@ +import { cn } from '../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type StructureIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export const StructureIcon = (props: StructureIconProps) => { + const { className, size = 'sm', ...res } = props + return ( + + Structure Icon + + + + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/fbd/Block.tsx b/src2/renderer/assets/icons/project/fbd/Block.tsx new file mode 100644 index 000000000..6d551712a --- /dev/null +++ b/src2/renderer/assets/icons/project/fbd/Block.tsx @@ -0,0 +1,55 @@ +import { cn } from '../../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IBlockIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} +export default function BlockIcon(props: IBlockIconProps) { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/fbd/Comment.tsx b/src2/renderer/assets/icons/project/fbd/Comment.tsx new file mode 100644 index 000000000..b12e79942 --- /dev/null +++ b/src2/renderer/assets/icons/project/fbd/Comment.tsx @@ -0,0 +1,34 @@ +import { cn } from '../../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type ICommentIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} +export default function CommentIcon(props: ICommentIconProps) { + const { className, size = 'sm', ...res } = props + return ( + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/fbd/Connector.tsx b/src2/renderer/assets/icons/project/fbd/Connector.tsx new file mode 100644 index 000000000..75f0b158c --- /dev/null +++ b/src2/renderer/assets/icons/project/fbd/Connector.tsx @@ -0,0 +1,36 @@ +import { cn } from '../../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IBlockIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export default function ConnectorIcon(props: IBlockIconProps) { + const { className, size = 'sm', ...res } = props + return ( + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/fbd/Continuation.tsx b/src2/renderer/assets/icons/project/fbd/Continuation.tsx new file mode 100644 index 000000000..bcc3156a6 --- /dev/null +++ b/src2/renderer/assets/icons/project/fbd/Continuation.tsx @@ -0,0 +1,36 @@ +import { cn } from '../../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IBlockIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export default function ContinuationIcon(props: IBlockIconProps) { + const { className, size = 'sm', ...res } = props + return ( + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/fbd/VariableIn.tsx b/src2/renderer/assets/icons/project/fbd/VariableIn.tsx new file mode 100644 index 000000000..eed3fd2cf --- /dev/null +++ b/src2/renderer/assets/icons/project/fbd/VariableIn.tsx @@ -0,0 +1,41 @@ +import { cn } from '../../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IBlockIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export default function VariableInIcon(props: IBlockIconProps) { + const { className, size = 'sm', ...res } = props + return ( + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/fbd/VariableInOut.tsx b/src2/renderer/assets/icons/project/fbd/VariableInOut.tsx new file mode 100644 index 000000000..e0b0677df --- /dev/null +++ b/src2/renderer/assets/icons/project/fbd/VariableInOut.tsx @@ -0,0 +1,42 @@ +import { cn } from '../../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IBlockIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export default function VariableInOutIcon(props: IBlockIconProps) { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/fbd/VariableOut.tsx b/src2/renderer/assets/icons/project/fbd/VariableOut.tsx new file mode 100644 index 000000000..27ad5c538 --- /dev/null +++ b/src2/renderer/assets/icons/project/fbd/VariableOut.tsx @@ -0,0 +1,41 @@ +import { cn } from '../../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IBlockIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export default function VariableOutIcon(props: IBlockIconProps) { + const { className, size = 'sm', ...res } = props + return ( + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/ladder/Block.tsx b/src2/renderer/assets/icons/project/ladder/Block.tsx new file mode 100644 index 000000000..0747dd949 --- /dev/null +++ b/src2/renderer/assets/icons/project/ladder/Block.tsx @@ -0,0 +1,55 @@ +import { cn } from '../../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' + +type IBlockIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} + +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} +export default function BlockIcon(props: IBlockIconProps) { + const { className, size = 'sm', ...res } = props + return ( + + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/ladder/Coil.tsx b/src2/renderer/assets/icons/project/ladder/Coil.tsx new file mode 100644 index 000000000..23c15bdb2 --- /dev/null +++ b/src2/renderer/assets/icons/project/ladder/Coil.tsx @@ -0,0 +1,40 @@ +import { cn } from '../../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' +type ICoilIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export default function CoilIcon(props: ICoilIconProps) { + const { className, size = 'sm', ...res } = props + + return ( + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/project/ladder/Contact.tsx b/src2/renderer/assets/icons/project/ladder/Contact.tsx new file mode 100644 index 000000000..68b39affc --- /dev/null +++ b/src2/renderer/assets/icons/project/ladder/Contact.tsx @@ -0,0 +1,34 @@ +import { cn } from '../../../../../utils/cn' +import { ComponentPropsWithoutRef } from 'react' +type IContactIconProps = ComponentPropsWithoutRef<'svg'> & { + size?: 'sm' | 'md' | 'lg' +} +const sizeClasses = { + sm: 'w-5 h-5', + md: 'w-6 h-6', + lg: 'w-12 h-12', +} + +export default function ContactIcon(props: IContactIconProps) { + const { className, size = 'sm', ...res } = props + + return ( + + + + + + + + ) +} diff --git a/src2/renderer/assets/icons/window-controls/Close.tsx b/src2/renderer/assets/icons/window-controls/Close.tsx new file mode 100644 index 000000000..1331d3759 --- /dev/null +++ b/src2/renderer/assets/icons/window-controls/Close.tsx @@ -0,0 +1,10 @@ +const CloseWindowIcon = () => { + return ( + + Close + + + ) +} + +export { CloseWindowIcon } diff --git a/src2/renderer/assets/icons/window-controls/Exit-Maximize.tsx b/src2/renderer/assets/icons/window-controls/Exit-Maximize.tsx new file mode 100644 index 000000000..ed2eb4d08 --- /dev/null +++ b/src2/renderer/assets/icons/window-controls/Exit-Maximize.tsx @@ -0,0 +1,28 @@ +const ExitMaximizeIcon = () => { + return ( + + + + + + + + + + + + ) +} + +export { ExitMaximizeIcon } diff --git a/src2/renderer/assets/icons/window-controls/Maximize.tsx b/src2/renderer/assets/icons/window-controls/Maximize.tsx new file mode 100644 index 000000000..235169efa --- /dev/null +++ b/src2/renderer/assets/icons/window-controls/Maximize.tsx @@ -0,0 +1,15 @@ +const MaximizeIcon = () => { + return ( + + Maximize + + + ) +} + +export { MaximizeIcon } diff --git a/src2/renderer/assets/icons/window-controls/Minimize.tsx b/src2/renderer/assets/icons/window-controls/Minimize.tsx new file mode 100644 index 000000000..3df3ba927 --- /dev/null +++ b/src2/renderer/assets/icons/window-controls/Minimize.tsx @@ -0,0 +1,10 @@ +const MinimizeIcon = () => { + return ( + + Minimize + + + ) +} + +export { MinimizeIcon } diff --git a/src2/renderer/assets/images/example.png b/src2/renderer/assets/images/example.png new file mode 100644 index 000000000..2f8ca3960 Binary files /dev/null and b/src2/renderer/assets/images/example.png differ diff --git a/src2/renderer/assets/index.ts b/src2/renderer/assets/index.ts new file mode 100644 index 000000000..826dac455 --- /dev/null +++ b/src2/renderer/assets/index.ts @@ -0,0 +1 @@ +export * from './icons' diff --git a/src2/renderer/data/constants/icon-styles.ts b/src2/renderer/data/constants/icon-styles.ts new file mode 100644 index 000000000..e980de745 --- /dev/null +++ b/src2/renderer/data/constants/icon-styles.ts @@ -0,0 +1,22 @@ +export const IconStyles = { + colorClasses: { + /** Here gonna be put the common Tailwind classes related to color of the icons */ + }, + sizeClasses: { + small: { + sm: 'w-5 h-5', + md: 'w-7 h-7', + lg: 'w-10 h-10', + }, + medium: { + sm: 'w-5 h-5', + md: 'w-8 h-8', + lg: 'w-12 h-12', + }, + large: { + sm: 'w-7 h-7', + md: 'w-10 h-10', + lg: 'w-14 h-14', + }, + }, +} diff --git a/src2/renderer/data/index.ts b/src2/renderer/data/index.ts new file mode 100644 index 000000000..67cb75907 --- /dev/null +++ b/src2/renderer/data/index.ts @@ -0,0 +1 @@ +export { IconStyles } from './constants/icon-styles' diff --git a/src2/renderer/styles/globals.css b/src2/renderer/styles/globals.css new file mode 100644 index 000000000..63ca18720 --- /dev/null +++ b/src2/renderer/styles/globals.css @@ -0,0 +1,207 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +::-webkit-scrollbar { + display: flex; + height: 0.25rem; + width: 0.25rem; + border-radius: 0.5rem; + background-color: rgb(221 226 232 / var(--tw-bg-opacity)); + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 160ms; + @apply dark:bg-neutral-850; +} + +::-webkit-scrollbar-thumb { + border-radius: 0.5rem; + background-color: var(--primary-medium); + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 700ms; + @apply bg-opacity-30 hover:bg-brand-medium hover:bg-opacity-100; +} + +::-webkit-scrollbar-corner { + background-color: transparent; +} + +@layer base { + :root { + --primary-default: #0464fb; + --primary-light: #b4d0fe; + --primary-medium: #0350c9; + --primary-medium-dark: #023c97; + --primary-dark: #011e4b; + /* Fallback variables to set the height of the titlebar based on OS */ + --oplc-title-bar-height: 2rem; + --fallback-darwin-title-bar-height: 1.75rem; + --radix-popper-transform-origin: 100% 0px; + /* Viewport height variable for proper mobile/tablet support */ + --app-vh: 100vh; + } + + /* Use small viewport height (svh) for stable sizing on mobile/tablet */ + @supports (height: 100svh) { + :root { + --app-vh: 100svh; + } + } + + /* Fallback to dynamic viewport height (dvh) if svh not supported */ + @supports (height: 100dvh) and (not (height: 100svh)) { + :root { + --app-vh: 100dvh; + } + } + + /* Prevent scrolling on tablets and mobile devices */ + html { + width: 100%; + height: 100%; + overflow: hidden; + } + + /* Prevent selection of UI elements except for user-typed text */ + body { + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + width: 100%; + height: 100%; + overflow: hidden; + -webkit-overflow-scrolling: touch; + } + + /* Allow selection only in text input areas */ + input, + textarea, + [contenteditable='true'] { + user-select: text; + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + } + + /* This can be useful to allocate the main container */ + + #folder-root p:hover ~ svg #folder-path { + fill: var(--primary-medium-dark); + } + + button { + outline: 2px solid transparent; + outline-offset: 2px; + } +} + +@layer components { + .box { + @apply border border-brand-light shadow-oplc dark:border-brand-medium-dark dark:shadow-oplc-dark; + } + /* Classes for the custom titlebar*/ + .oplc-titlebar-container { + position: absolute; + top: 0; + width: 100%; + height: var(--oplc-title-bar-height); + } + + .oplc-titlebar-content { + position: absolute; + top: 0; + display: flex; + user-select: none; + height: 100%; + background-color: var(--primary-dark); + left: 0; + width: 100%; + } + + .oplc-titlebar-drag-region { + app-region: drag; + } + + .oplc-main-content { + position: absolute; + display: flex; + left: 0; + right: 0; + bottom: 0; + top: var(--oplc-title-bar-height); + overflow: hidden; + } + input[type='number']::-webkit-outer-spin-button, + input[type='number']::-webkit-inner-spin-button { + appearance: none; + margin: 0; + } + input[type='number'] { + appearance: textfield; + } +} + +@layer utilities { + .press-animated { + @apply border-[none] transition-[0.2s] duration-[all] active:scale-[0.90]; + } + + .no-drag-window { + -webkit-app-region: no-drag; + } +} + +.apexcharts-yaxis-label tspan, +.apexcharts-xaxis-label tspan { + @apply fill-neutral-1000 !text-[10px] dark:fill-neutral-50; +} + +@keyframes spin-refresh { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +.spin-refresh { + animation: spin-refresh 0.5s linear; +} + +/* Monaco Editor z-index constraints to prevent sticky scroll from overlapping dialogs */ +/* Target only Monaco's overlay widgets without affecting layout containers */ +.oplc-monaco-wrapper .monaco-editor .sticky-widget { + z-index: 1 !important; +} + +/* Ensure Monaco's other overlay widgets stay below dialogs but above editor content */ +.oplc-monaco-wrapper .monaco-editor .suggest-widget, +.oplc-monaco-wrapper .monaco-editor .monaco-hover, +.oplc-monaco-wrapper .monaco-editor .parameter-hints-widget { + z-index: 10 !important; +} + +/* Debug inline value badges for ST/IL editors during debug sessions */ +.oplc-monaco-wrapper .debug-inline-value { + color: #ffffff; + background-color: #2e7d32; + padding: 0px 6px; + border-radius: 3px; + font-size: 11px; + font-weight: 600; + margin-left: 8px; +} + +.dark .oplc-monaco-wrapper .debug-inline-value { + background-color: #388e3c; +} + +/* Ensure Radix popper/select content sits well above Monaco */ +[data-radix-popper-content-wrapper], +[data-radix-select-content], +[role='listbox'] { + z-index: 1000 !important; +} diff --git a/src2/shared/data/mock/examples.json b/src2/shared/data/mock/examples.json new file mode 100644 index 000000000..f38258e4c --- /dev/null +++ b/src2/shared/data/mock/examples.json @@ -0,0 +1,92 @@ +[ + { + "id": "e1182fc6-5886-4b6e-b5fb-071a48cb40b5", + "name": "Ligula.ppt", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "8a899345-522c-451a-a4bf-86b85880d839", + "name": "AmetLobortis.jpeg", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "468b6247-fc31-402b-a368-917756f8a97b", + "name": "Est.ppt", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "dfc0b806-dcac-46c0-a4d1-4801c06075c5", + "name": "MorbiVelLectus.avi", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "c9a5c92b-6f05-4914-8169-1b16c5553b89", + "name": "Rhoncus.ppt", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "e2cec6b4-46b6-4edb-aff1-efc12de511fc", + "name": "SedAnte.xls", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "f612da86-55b4-468b-8743-57f2803be706", + "name": "LeoOdioCondimentum.ppt", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "0d97670b-89cf-45ae-afd7-f92d297d4977", + "name": "Varius.jpeg", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "120ca18d-8e00-4097-9e47-4afba2a52557", + "name": "MolestieHendrerit.xls", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "84066f0f-32d7-479c-8c10-3442fce5683e", + "name": "EratErosViverra.tiff", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "3e58d688-bcd3-4553-9159-6390e7d6d0e1", + "name": "NamUltrices.xls", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "bf64d9d7-f5dd-4a99-87f8-323d74b10bfc", + "name": "Quisque.xls", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "d438ec6f-e3f4-448b-bb9c-43ffeac03ca1", + "name": "Quam.mp3", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "0ddb0a10-1311-47c7-bd33-3d4b49015dc8", + "name": "Vel.mp3", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + }, + { + "id": "90dcb5d4-10c2-4271-9212-6a5b5404230a", + "name": "CumSociis.ppt", + "description": "This is a description for example", + "source_img": "../assets/images/example.png" + } +] diff --git a/src2/shared/data/mock/object-to-create-project.ts b/src2/shared/data/mock/object-to-create-project.ts new file mode 100644 index 000000000..343f854cc --- /dev/null +++ b/src2/shared/data/mock/object-to-create-project.ts @@ -0,0 +1,59 @@ +import { formatDate } from '../../../utils' + +const xmlProjectAsObject = { + project: { + '@xmlns': 'http://www.plcopen.org/xml/tc6_0201', + '@xmlns:ns1': 'http://www.plcopen.org/xml/tc6.xsd', + '@xmlns:xhtml': 'http://www.w3.org/1999/xhtml', + '@xmlns:xsd': 'http://www.w3.org/2001/XMLSchema-instance', + '@xsi:schemaLocation': 'http://www.plcopen.org/xml/tc6_0200 http://www.plcopen.org/xml/tc6_0200', + fileHeader: { + '@companyName': 'Unknown', + '@creationDateTime': formatDate(new Date()), + '@productName': 'Unnamed', + '@productVersion': '1', + }, + contentHeader: { + '@name': 'Unnamed', + '@modificationDateTime': formatDate(new Date()), + coordinateInfo: { + fbd: { + scaling: { + '@x': '16', + '@y': '16', + }, + }, + ld: { + scaling: { + '@x': '10', + '@y': '10', + }, + }, + sfc: { + scaling: { + '@x': '10', + '@y': '10', + }, + }, + }, + }, + types: { + dataTypes: {}, + pous: { + pou: [], + }, + }, + instances: { + configurations: { + configuration: { + '@name': 'Config0', + resource: { + '@name': 'Res0', + }, + }, + }, + }, + }, +} + +export default xmlProjectAsObject diff --git a/src2/shared/data/mock/projects-data.json b/src2/shared/data/mock/projects-data.json new file mode 100644 index 000000000..2ea717fb1 --- /dev/null +++ b/src2/shared/data/mock/projects-data.json @@ -0,0 +1,252 @@ +[ + { + "id": "4c9094ea-07a7-45d0-9231-8d623c992bd9", + "name": "Feedspan", + "last_modified": "1:26 AM" + }, + { + "id": "b6b9fe58-0b38-4b0c-9059-b57e4ac6b2b4", + "name": "Realblab", + "last_modified": "6:14 PM" + }, + { + "id": "92c5f62a-579a-4da7-9114-74aa8f0d2983", + "name": "Zoomzone", + "last_modified": "9:20 PM" + }, + { + "id": "9400065c-0dfb-4e60-9a82-938b5bbb289d", + "name": "Wordpedia", + "last_modified": "1:51 AM" + }, + { + "id": "6dc64ca0-5865-4016-941b-857663583baf", + "name": "Edgepulse", + "last_modified": "1:39 AM" + }, + { + "id": "b1351350-cfc2-4c49-a829-152655f82882", + "name": "Oozz", + "last_modified": "10:39 AM" + }, + { + "id": "6e874a30-275c-40e4-99b3-4cc68fab2d33", + "name": "Rhyzio", + "last_modified": "1:12 PM" + }, + { + "id": "6cfd9e3b-22fe-4198-9f15-045b99fef7c8", + "name": "Bubblemix", + "last_modified": "11:48 AM" + }, + { + "id": "628ba4a8-52b9-42a5-b525-bbda2c1ea92c", + "name": "JumpXS", + "last_modified": "2:25 AM" + }, + { + "id": "3f44685d-0fa0-4b22-aba9-24e8fdf37b6f", + "name": "Zoomlounge", + "last_modified": "2:43 AM" + }, + { + "id": "3b24919b-334c-4702-bd3a-95094b485678", + "name": "Oyope", + "last_modified": "12:37 AM" + }, + { + "id": "52670319-751d-49ed-9c9a-0579de19394b", + "name": "Riffwire", + "last_modified": "5:40 AM" + }, + { + "id": "d8780061-6980-48c5-81ba-2ecb88247a2b", + "name": "Wikido", + "last_modified": "9:05 AM" + }, + { + "id": "762ae4f8-e4f7-4e0b-ae2d-7ed28b60e120", + "name": "Dabshots", + "last_modified": "7:15 AM" + }, + { + "id": "a687f254-e404-4536-80ad-1efd41ca4ec2", + "name": "Skyndu", + "last_modified": "1:48 AM" + }, + { + "id": "5be549f0-7085-447a-ad09-86435d8e0bf1", + "name": "Jetwire", + "last_modified": "12:01 PM" + }, + { + "id": "2fafef73-49de-46df-8bec-d9f9ad08f672", + "name": "Skynoodle", + "last_modified": "2:52 PM" + }, + { + "id": "6e0d3657-0ac6-4c18-985b-e646d11f962c", + "name": "BlogXS", + "last_modified": "11:13 AM" + }, + { + "id": "478148cd-850b-48e4-8e2c-9a0740c049f4", + "name": "Aimbo", + "last_modified": "6:33 PM" + }, + { + "id": "d80b8780-e0da-426b-9c99-b534a5ffa9a7", + "name": "Pixope", + "last_modified": "1:50 AM" + }, + { + "id": "6348553b-e7e5-4a4f-9c86-ead12cd4d6ab", + "name": "Camido", + "last_modified": "7:23 PM" + }, + { + "id": "cf306a9b-93e8-4e68-af68-50832a4384f9", + "name": "Avavee", + "last_modified": "5:06 PM" + }, + { + "id": "fd73b9cc-6375-411f-a935-5697e61c3ccc", + "name": "Nlounge", + "last_modified": "12:37 AM" + }, + { + "id": "22dc5774-a278-497e-a8be-a188c95dd9ca", + "name": "Photobean", + "last_modified": "11:25 PM" + }, + { + "id": "751917ee-ca1f-43e1-9580-2a52af54ec99", + "name": "Ozu", + "last_modified": "11:17 AM" + }, + { + "id": "6a8d4c75-b86e-4aa6-a3a7-5cd48e480a06", + "name": "Blogpad", + "last_modified": "7:16 PM" + }, + { + "id": "10874064-a929-4ca7-95dd-96c358916ecc", + "name": "Voomm", + "last_modified": "5:17 AM" + }, + { + "id": "ee86e258-a8ac-41dd-9a81-56968fb9ccf5", + "name": "Livetube", + "last_modified": "2:26 AM" + }, + { + "id": "98953822-f65f-4b65-a08b-c10643a874ba", + "name": "Minyx", + "last_modified": "3:21 PM" + }, + { + "id": "79bc03c8-daef-4f14-819f-53628a71fc3d", + "name": "Gigazoom", + "last_modified": "9:58 AM" + }, + { + "id": "38b7c26b-6ad7-474b-8f02-afa676d7c33a", + "name": "Youspan", + "last_modified": "4:48 PM" + }, + { + "id": "d1bcfe9a-9800-40ee-8544-d7a5b9b7f75c", + "name": "Realbridge", + "last_modified": "9:43 AM" + }, + { + "id": "9dd6f9fa-7130-479b-a389-500ea18408ad", + "name": "Zooxo", + "last_modified": "10:18 PM" + }, + { + "id": "42692e37-9b47-4845-9058-9b0c0a5adf71", + "name": "Katz", + "last_modified": "9:30 AM" + }, + { + "id": "b2b0aa30-550c-459b-83cd-6fedbae11902", + "name": "Trupe", + "last_modified": "6:08 PM" + }, + { + "id": "43541ed8-ddc8-4370-9464-0da97faa9648", + "name": "Fadeo", + "last_modified": "7:25 PM" + }, + { + "id": "fd3dd7a7-2d7e-4074-97d1-ba95ce4eda2b", + "name": "Jetpulse", + "last_modified": "4:34 PM" + }, + { + "id": "e7706f17-5f03-4094-9427-a26b9319d639", + "name": "Photofeed", + "last_modified": "6:37 PM" + }, + { + "id": "a39ca8ea-7464-4daa-830c-5cc4719700db", + "name": "Skivee", + "last_modified": "1:40 PM" + }, + { + "id": "59838216-5162-4c02-b952-3f937ea2fbf0", + "name": "Oozz", + "last_modified": "10:05 AM" + }, + { + "id": "2345ab43-347c-496c-93d9-331c4b9a569f", + "name": "Jayo", + "last_modified": "3:44 PM" + }, + { + "id": "6d2f410b-3a5e-435a-aa39-9b48bc666291", + "name": "Muxo", + "last_modified": "8:52 AM" + }, + { + "id": "4fc66bda-52a0-4b84-af7f-01d26d4639fd", + "name": "Skinte", + "last_modified": "2:26 PM" + }, + { + "id": "f3927048-7694-41cd-9e54-1aec83bcae98", + "name": "Omba", + "last_modified": "6:20 PM" + }, + { + "id": "0e4053fd-ce67-4ca1-a33a-ae7c604954bf", + "name": "Jamia", + "last_modified": "7:18 PM" + }, + { + "id": "8b80bdb1-838a-40f1-83ba-5001ba02b6a7", + "name": "Skimia", + "last_modified": "5:00 AM" + }, + { + "id": "1eb9ccad-da82-4fa6-bf81-770c28a828de", + "name": "Divape", + "last_modified": "8:22 AM" + }, + { + "id": "157543e8-8683-4a49-8d42-adfa80ba3e2a", + "name": "Photospace", + "last_modified": "5:51 AM" + }, + { + "id": "8b150aee-82ce-48d7-9bc1-c26aa758b182", + "name": "Tazz", + "last_modified": "12:06 PM" + }, + { + "id": "aa373003-8e7a-4d7c-a133-c9a5eb312258", + "name": "Realmix", + "last_modified": "8:21 PM" + } +] diff --git a/src2/utils/__tests__/cn.test.ts b/src2/utils/__tests__/cn.test.ts new file mode 100644 index 000000000..bd40cc71d --- /dev/null +++ b/src2/utils/__tests__/cn.test.ts @@ -0,0 +1,27 @@ +import { cn } from '../cn' + +describe('cn', () => { + it('merges class names', () => { + expect(cn('foo', 'bar')).toBe('foo bar') + }) + + it('handles conditional classes', () => { + expect(cn('foo', false && 'bar', 'baz')).toBe('foo baz') + }) + + it('merges tailwind classes with last-wins', () => { + expect(cn('p-4', 'p-2')).toBe('p-2') + }) + + it('handles undefined and null inputs', () => { + expect(cn('foo', undefined, null, 'bar')).toBe('foo bar') + }) + + it('handles empty inputs', () => { + expect(cn()).toBe('') + }) + + it('handles array inputs', () => { + expect(cn(['foo', 'bar'])).toBe('foo bar') + }) +}) diff --git a/src2/utils/__tests__/format-date.test.ts b/src2/utils/__tests__/format-date.test.ts new file mode 100644 index 000000000..0c91254bf --- /dev/null +++ b/src2/utils/__tests__/format-date.test.ts @@ -0,0 +1,23 @@ +import { formatDate } from '../format-date' + +describe('formatDate', () => { + it('formats a date as ISO-like string without timezone', () => { + const date = new Date(2026, 2, 11, 14, 30, 5) // March 11, 2026 14:30:05 + expect(formatDate(date)).toBe('2026-03-11T14:30:05') + }) + + it('pads single-digit months and days', () => { + const date = new Date(2026, 0, 5, 9, 3, 7) // Jan 5, 2026 09:03:07 + expect(formatDate(date)).toBe('2026-01-05T09:03:07') + }) + + it('handles midnight', () => { + const date = new Date(2026, 11, 31, 0, 0, 0) // Dec 31, 2026 00:00:00 + expect(formatDate(date)).toBe('2026-12-31T00:00:00') + }) + + it('handles end of day', () => { + const date = new Date(2026, 5, 15, 23, 59, 59) // Jun 15, 2026 23:59:59 + expect(formatDate(date)).toBe('2026-06-15T23:59:59') + }) +}) diff --git a/src2/utils/cn.ts b/src2/utils/cn.ts new file mode 100644 index 000000000..c8498c564 --- /dev/null +++ b/src2/utils/cn.ts @@ -0,0 +1,4 @@ +import { ClassValue, clsx } from 'clsx' +import { twMerge } from 'tailwind-merge' + +export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs)) diff --git a/src2/utils/format-date.ts b/src2/utils/format-date.ts new file mode 100644 index 000000000..8b25496da --- /dev/null +++ b/src2/utils/format-date.ts @@ -0,0 +1,8 @@ +const padTo2Digits = (num: number) => num.toString().padStart(2, '0') + +export const formatDate = (date: Date) => + `${[date.getFullYear(), padTo2Digits(date.getMonth() + 1), padTo2Digits(date.getDate())].join('-')}T${[ + padTo2Digits(date.getHours()), + padTo2Digits(date.getMinutes()), + padTo2Digits(date.getSeconds()), + ].join(':')}` diff --git a/src2/utils/index.ts b/src2/utils/index.ts index b99629f02..47c25e206 100644 --- a/src2/utils/index.ts +++ b/src2/utils/index.ts @@ -8,3 +8,5 @@ export { } from './plc-constants' export type { PLCBaseType } from './plc-constants' export { CONSTANTS } from './app-constants' +export { cn } from './cn' +export { formatDate } from './format-date'