feat(web/ui): unify config sections, restore home padding, improve project repos

- Add shared .config-section component class and migrate Tool Workshop
  and Config Profiles editors to use it.
- Restore --space-4 padding on home hero, summary cards, and sections
  with --space-3 on mobile.
- Restructure expandable project card: add 'Repositories' header with
  repo count and move 'Add Repository' button into the section header.
- Left-align repository blocks so they fill from the project detail edge.
This commit is contained in:
Developer
2026-06-16 15:55:58 +00:00
parent cbd5533adf
commit 972dae64f2
5 changed files with 235 additions and 134 deletions
@@ -173,9 +173,12 @@ export const ConfigProfileEditorPanel = ({
</label>
</div>
<div className="form-section">
<div className="row justify-between items-center mb-3">
<h4 className="m-0">Includes</h4>
<section className="config-section">
<div className="config-section-header">
<div>
<h4 className="config-section-title">Includes</h4>
<p className="config-section-subtitle">Compose configurations from other profiles</p>
</div>
<span className="muted text-sm">{includedProfileIds.length} included</span>
</div>
{includedProfileIds.length === 0 ? (
@@ -216,10 +219,10 @@ export const ConfigProfileEditorPanel = ({
</select>
</div>
)}
</div>
</section>
<div className="form-section">
<h4 className="m-0 mb-3">Environment Variables</h4>
<section className="config-section">
<h4 className="config-section-title">Environment Variables</h4>
{Object.entries(formData.env_vars || {}).map(([key, value], idx) => (
<div key={idx} className="form-row row-sm mb-2">
<input type="text" value={key} onChange={(e) => onUpdateEnvVar(key, e.target.value, value)} placeholder="VAR_NAME" className="form-input" />
@@ -228,16 +231,20 @@ export const ConfigProfileEditorPanel = ({
</div>
))}
<button type="button" className="secondary-button" onClick={onAddEnvVar}><Icon name="add" size="sm" /> Add Variable</button>
</div>
</section>
<div className="form-section">
<h4 className="m-0 mb-3">Runtime Hints</h4>
<section className="config-section">
<h4 className="config-section-title">Runtime Hints</h4>
<textarea value={JSON.stringify(formData.runtime_hints || {}, null, 2)} onChange={(e) => { try { const parsed = JSON.parse(e.target.value); onFormChange("runtime_hints", parsed); } catch { /* ignore */ } }} placeholder='{"start_command": "npm start"}' rows={4} className="form-input font-mono text-sm" />
</div>
</section>
<div className="form-section">
<h4 className="m-0 mb-2">Files</h4>
<p className="muted text-sm m-0 mb-3">Relative paths written to the instance directory. Use Mounts below for absolute container paths.</p>
<section className="config-section">
<div className="config-section-header">
<div>
<h4 className="config-section-title">Files</h4>
<p className="config-section-subtitle">Relative paths written to the instance directory</p>
</div>
</div>
{Object.entries(formData.files || {}).map(([path, content], idx) => (
<div key={idx} className="card-sm mb-2">
<div className="form-row row-sm mb-2">
@@ -248,11 +255,15 @@ export const ConfigProfileEditorPanel = ({
</div>
))}
<button type="button" className="secondary-button" onClick={onAddFile}><Icon name="add" size="sm" /> Add File</button>
</div>
</section>
<div className="form-section">
<h4 className="m-0 mb-2">Mounts</h4>
<p className="muted text-sm m-0 mb-3">Bind directories into the container at absolute paths. Files are relative to the mount target.</p>
<section className="config-section">
<div className="config-section-header">
<div>
<h4 className="config-section-title">Mounts</h4>
<p className="config-section-subtitle">Bind directories into the container at absolute paths</p>
</div>
</div>
{(formData.mounts || []).map((mount, index) => (
<div key={index} className="card-sm mb-3">
<div className="form-row row-sm mb-3">
@@ -276,11 +287,12 @@ export const ConfigProfileEditorPanel = ({
</div>
))}
<button type="button" className="secondary-button" onClick={onAddMount}><Icon name="add" size="sm" /> Add Mount</button>
</div>
</section>
<div className="form-section">
<section className="config-section">
<h4 className="config-section-title">Git Mounts</h4>
<GitMountEditor mounts={formData.git_mounts || []} onChange={(git_mounts) => onFormChange("git_mounts", git_mounts)} />
</div>
</section>
<div className="dialog-actions sticky-footer">
<button type="submit" disabled={saveStatus === "saving"} className="btn btn-primary">