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 (
+
+ )
+}
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 (
+
+ )
+}
+
+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 (
+
+ )
+}
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 (
+
+ )
+}
+
+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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
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 (
+
+ )
+}
+
+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 (
+
+ )
+}
+
+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 (
+
+ )
+}
+
+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'