From 1c13e068adf9b7c3497f020f4e5aad352e66b781 Mon Sep 17 00:00:00 2001 From: Andrii Arsenin Date: Fri, 10 Apr 2026 15:53:26 +0300 Subject: [PATCH] feat(ui): add CodeBlock and CodeEditor components with Monaco and hljs - add CodeBlock for read-only syntax-highlighted display (hljs, js/json) - add CodeEditor wrapping Monaco editor with theme sync, focus state, and error state - replace code textareas in snippet, credential, and step pages with CodeEditor - replace code
 blocks in snippet and credential detail pages with CodeBlock
- make form cards full-width on pages with code editors
- add resize:vertical support to CodeEditor wrapper with automaticLayout
---
 client/package.json                           |  2 +
 client/src/lib/hljs.ts                        | 12 +++
 client/src/pages/Page.module.css              |  4 +
 .../pages/credential/CreateCredentialPage.tsx | 32 ++++---
 .../pages/credential/CredentialDetailPage.tsx | 12 +--
 .../src/pages/credential/CredentialsPage.tsx  |  4 +-
 .../pages/credential/EditCredentialPage.tsx   | 32 ++++---
 client/src/pages/scenario/CreateStepPage.tsx  |  4 +-
 client/src/pages/scenario/EditStepPage.tsx    | 22 ++---
 .../src/pages/scenario/ScenarioDetailPage.tsx |  4 +-
 client/src/pages/scenario/ScenariosPage.tsx   |  4 +-
 .../src/pages/snippet/CreateSnippetPage.tsx   | 16 ++--
 client/src/pages/snippet/EditSnippetPage.tsx  | 16 ++--
 .../src/pages/snippet/SnippetDetailPage.tsx   |  7 +-
 client/src/pages/snippet/SnippetsPage.tsx     |  4 +-
 client/src/ui/CodeBlock/CodeBlock.module.css  | 76 +++++++++++++++++
 client/src/ui/CodeBlock/CodeBlock.tsx         | 27 ++++++
 .../src/ui/CodeEditor/CodeEditor.module.css   | 18 ++++
 client/src/ui/CodeEditor/CodeEditor.tsx       | 83 +++++++++++++++++++
 client/src/ui/index.ts                        |  6 ++
 package-lock.json                             | 82 ++++++++++++++++++
 21 files changed, 391 insertions(+), 76 deletions(-)
 create mode 100644 client/src/lib/hljs.ts
 create mode 100644 client/src/ui/CodeBlock/CodeBlock.module.css
 create mode 100644 client/src/ui/CodeBlock/CodeBlock.tsx
 create mode 100644 client/src/ui/CodeEditor/CodeEditor.module.css
 create mode 100644 client/src/ui/CodeEditor/CodeEditor.tsx

diff --git a/client/package.json b/client/package.json
index e136da7..4a39c02 100644
--- a/client/package.json
+++ b/client/package.json
@@ -14,6 +14,8 @@
     "format": "prettier --write \"src/**/*.{ts,tsx}\" \".storybook/**/*.{ts,tsx}\""
   },
   "dependencies": {
+    "@monaco-editor/react": "^4.7.0",
+    "highlight.js": "^11.11.1",
     "i18next": "^26.0.4",
     "lucide-react": "^1.7.0",
     "moment": "^2.30.1",
diff --git a/client/src/lib/hljs.ts b/client/src/lib/hljs.ts
new file mode 100644
index 0000000..d8a1cde
--- /dev/null
+++ b/client/src/lib/hljs.ts
@@ -0,0 +1,12 @@
+import hljs from 'highlight.js/lib/core';
+import javascript from 'highlight.js/lib/languages/javascript';
+import json from 'highlight.js/lib/languages/json';
+
+hljs.registerLanguage('javascript', javascript);
+hljs.registerLanguage('json', json);
+
+export default hljs;
+
+export function escapeHtml(str: string): string {
+  return str.replace(/&/g, '&').replace(//g, '>');
+}
diff --git a/client/src/pages/Page.module.css b/client/src/pages/Page.module.css
index d495478..370d20e 100644
--- a/client/src/pages/Page.module.css
+++ b/client/src/pages/Page.module.css
@@ -196,6 +196,10 @@
   max-width: 540px;
 }
 
+.formCardFull {
+  max-width: none;
+}
+
 .formFields {
   display: flex;
   flex-direction: column;
diff --git a/client/src/pages/credential/CreateCredentialPage.tsx b/client/src/pages/credential/CreateCredentialPage.tsx
index 2e56606..4d6a2e6 100644
--- a/client/src/pages/credential/CreateCredentialPage.tsx
+++ b/client/src/pages/credential/CreateCredentialPage.tsx
@@ -2,7 +2,7 @@ import { useState } from 'react';
 import { useNavigate } from 'react-router-dom';
 import { useTranslation } from 'react-i18next';
 import { credentials } from '../../api';
-import { Breadcrumbs, Button, Card, Input, Textarea } from '../../ui';
+import { Breadcrumbs, Button, Card, Input, CodeEditor } from '../../ui';
 import styles from '../Page.module.css';
 
 export function CreateCredentialPage() {
@@ -58,7 +58,7 @@ export function CreateCredentialPage() {
       {error && 

{error}

}
- +
-