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 <pre> 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
This commit is contained in:
2026-04-10 15:53:26 +03:00
parent 2046e64428
commit 1c13e068ad
21 changed files with 391 additions and 76 deletions
@@ -1,7 +1,8 @@
import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Download, Pencil, Trash2 } from 'lucide-react';
import { Upload, Pencil, Trash2 } from 'lucide-react';
import { CodeBlock } from '../../ui';
import { stringify as yamlStringify } from 'yaml';
import { credentials } from '../../api';
import type { Credential } from '../../api';
@@ -55,7 +56,7 @@ export function CredentialDetailPage() {
{credential && (
<div className={styles.toolbarActions}>
<Button variant="secondary" size="sm" onClick={handleExport}>
<Download size={14} />
<Upload size={14} />
{t('credentials.action_export')}
</Button>
<Button
@@ -116,15 +117,16 @@ export function CredentialDetailPage() {
<>
<h2 className={styles.sectionHeading}>{t('credentials.section_data')}</h2>
<Card>
<pre className={styles.codeBlock}>
{(() => {
<CodeBlock
language="json"
code={(() => {
try {
return JSON.stringify(JSON.parse(credential.data), null, 2);
} catch {
return credential.data;
}
})()}
</pre>
/>
</Card>
</>
)}