feat: JSON comments support + full-height layout
Some checks failed
CI / build-and-test (push) Has been cancelled
CI / build-and-test (pull_request) Has been cancelled

This commit is contained in:
sokol
2026-02-20 16:40:13 +03:00
parent c8f45e4962
commit 9f51379df9
4 changed files with 44 additions and 35 deletions

View File

@@ -98,7 +98,7 @@ function App() {
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100">
<main className="container mx-auto px-4 py-6 max-w-[1920px]">
<main className="container mx-auto px-4 py-6 max-w-[1920px] min-h-[calc(100vh-48px)]">
{/* Header */}
<div className="mb-6">
<FileChooser
@@ -112,10 +112,10 @@ function App() {
</div>
{envs.length > 0 ? (
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 min-h-[calc(100vh-200px)]">
{/* Environment Panel - 5/12 width */}
<section className="lg:col-span-5 xl:col-span-5 2xl:col-span-5">
<div className="sticky top-6">
<div className="sticky top-6 h-full">
<Environment
envs={envs}
onChanged={async (e) => await handleEnvChanged(e)}
@@ -127,7 +127,7 @@ function App() {
</section>
{/* Content Panel - 7/12 width */}
<section className="lg:col-span-7 xl:col-span-7 2xl:col-span-7">
<section className="lg:col-span-7 xl:col-span-7 2xl:col-span-7 h-full">
<Content
env={currentEnv}
config={config}

View File

@@ -34,33 +34,40 @@ export function ConfigTemplateEditor({ config, onSaved }: ConfigTemplateEditorPr
setMode('view');
}
function handleSave() {
// Validate JSON before saving (with placeholder support)
function validateJson(value: string): boolean {
try {
const sanitizedValue = draftContent.replace(/@[^@]+@/g, '1');
if (!value.trim()) {
setJsonError(null);
return true;
}
// Strip comments (// single-line and /* */ multi-line) and placeholders
const sanitizedValue = value
.replace(/\/\*[\s\S]*?\*\//g, '') // Remove /* */ comments
.replace(/\/\/.*$/gm, '') // Remove // comments
.replace(/@[^@]+@/g, '1'); // Replace placeholders
JSON.parse(sanitizedValue);
setJsonError(null);
onSaved(draftContent);
setMode('view');
return true;
} catch (e) {
setJsonError((e as Error).message);
return false;
}
}
function handleSave() {
// Validate JSON before saving (with comment and placeholder support)
if (validateJson(draftContent)) {
onSaved(draftContent);
setMode('view');
}
}
function handleDraftChange(value: string) {
setDraftContent(value);
// Validate JSON on every change
try {
if (value.trim()) {
const sanitizedValue = value.replace(/@[^@]+@/g, '1');
JSON.parse(sanitizedValue);
setJsonError(null);
} else {
setJsonError(null);
}
} catch (e) {
setJsonError((e as Error).message);
}
validateJson(value);
}
function handleKeyDown(e: React.KeyboardEvent<HTMLTextAreaElement>) {

View File

@@ -31,22 +31,24 @@ export function Content({ config, env, onTemplateSaved }: ContentProps) {
];
return (
<div className="bg-white rounded-xl shadow-lg border border-slate-200 overflow-hidden">
<Tabs tabs={tabs} activeTab={activeTab} onChange={setActiveTab} />
<div className="p-4">
<div className="bg-white rounded-xl shadow-lg border border-slate-200 overflow-hidden h-full flex flex-col">
<div className="flex-shrink-0">
<Tabs tabs={tabs} activeTab={activeTab} onChange={setActiveTab} />
</div>
<div className="flex-1 overflow-y-auto p-4 min-h-0">
<TabPanel isActive={activeTab === 'env'}>
<ContentParams env={env} />
</TabPanel>
<TabPanel isActive={activeTab === 'template'}>
<ConfigTemplateEditor config={config} onSaved={onTemplateSaved} />
</TabPanel>
<TabPanel isActive={activeTab === 'raw'}>
<ContentRaw config={config} env={env} />
</TabPanel>
<TabPanel isActive={activeTab === 'test'}>
<ContentTest config={config} env={env} />
</TabPanel>

View File

@@ -94,10 +94,10 @@ export function Environment({ envs, onChanged, onSelected, onAdd, onRemove }: En
));
return (
<Card variant="bordered" padding="none" className="h-full">
<CardBody className="space-y-1">
<Card variant="bordered" padding="none" className="h-full overflow-hidden flex flex-col">
<CardBody className="space-y-2 flex flex-col h-full overflow-hidden">
{/* Environment Selector */}
<div className="flex gap-2">
<div className="flex-shrink-0 flex gap-2">
<div className="flex-1">
<Select
label="Environment"
@@ -112,7 +112,7 @@ export function Environment({ envs, onChanged, onSelected, onAdd, onRemove }: En
/>
</div>
<div className="flex flex-col justify-center gap-2 pt-6">
<div className="flex flex-col justify-center gap-2 pt-6 flex-shrink-0">
<div className="flex gap-2">
<Button
variant="success"
@@ -134,13 +134,13 @@ export function Environment({ envs, onChanged, onSelected, onAdd, onRemove }: En
</div>
</div>
{/* Parameters Section */}
<div>
<h3 className="text-sm font-semibold text-slate-700 mb-1 uppercase tracking-wide">
{/* Parameters Section - Scrollable */}
<div className="flex-1 overflow-hidden flex flex-col min-h-0">
<h3 className="text-sm font-semibold text-slate-700 mb-1 uppercase tracking-wide flex-shrink-0">
Parameters
</h3>
<div className="space-y-0">
<div className="flex-1 overflow-y-auto space-y-0 pr-2 -mr-2">
{paramCtrls}
<EnvironmentParam