feat(web/ui): refactor component inline styles into utility classes
Pass 2 of the web UI spacing/typography/visual-rhythm rework. - Add layout, spacing, typography, visual, card, and component utilities - Add form-section, form-row, form-help, text-error, alert-success - Unify .form-group and .form-field; add .status-badge family - Alias legacy button classes to .btn primitives - Refactor ToolTypeListSidebar and ConfigProfileListSidebar to use .sidebar and var(--sidebar-width) instead of hardcoded 280px - Refactor ToolTypeEditorPanel, ConfigProfileEditorPanel, git-mount-editor, and manifest-editor to use utility classes Quality gates: npm run typecheck, npm run lint, npm run build pass. Inline style blocks in target components reduced from 198 to 11.
This commit is contained in:
@@ -53,35 +53,25 @@ export const ToolTypeEditorPanel = ({
|
||||
const hasSelection = isCreating || selectedToolType;
|
||||
|
||||
return (
|
||||
<div style={{ flex: 1, overflow: "auto", padding: "1.5rem", minWidth: 0 }}>
|
||||
<div className="flex-1 overflow-auto p-5 min-w-0">
|
||||
{!hasSelection ? (
|
||||
<div
|
||||
style={{
|
||||
textAlign: "center",
|
||||
paddingTop: "4rem",
|
||||
color: "var(--muted)",
|
||||
}}
|
||||
>
|
||||
<div style={{ opacity: 0.3, marginBottom: "1rem" }}>
|
||||
<div className="empty-state">
|
||||
<div className="empty-state-icon">
|
||||
<Icon name="code" size="lg" />
|
||||
</div>
|
||||
<h3 style={{ margin: "0 0 0.5rem 0", fontWeight: 500 }}>
|
||||
Select a tool type
|
||||
</h3>
|
||||
<p style={{ margin: 0 }}>
|
||||
Choose a tool from the list to edit, or create a new one.
|
||||
</p>
|
||||
<h3>Select a tool type</h3>
|
||||
<p>Choose a tool from the list to edit, or create a new one.</p>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<div style={{ marginBottom: "1.5rem" }}>
|
||||
<h1 style={{ margin: "0 0 0.5rem 0", fontSize: "1.5rem" }}>
|
||||
<div className="max-w-form">
|
||||
<div className="mb-5">
|
||||
<h1 className="m-0 mb-2 text-xl">
|
||||
{isCreating
|
||||
? "Create Tool Type"
|
||||
: selectedToolType?.display_name}
|
||||
</h1>
|
||||
{!isCreating && (
|
||||
<p className="muted" style={{ margin: 0 }}>
|
||||
<p className="muted m-0">
|
||||
{selectedToolType?.name} · {selectedToolType?.definition_type}{" "}
|
||||
·{" "}
|
||||
{selectedToolType?.interface_type === "web"
|
||||
@@ -91,11 +81,7 @@ export const ToolTypeEditorPanel = ({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<form
|
||||
onSubmit={onSubmit}
|
||||
className="stack"
|
||||
style={{ gap: "1rem", maxWidth: "800px" }}
|
||||
>
|
||||
<form onSubmit={onSubmit} className="stack stack-md">
|
||||
<div className="form-group">
|
||||
<label htmlFor="definition-type">Definition Type</label>
|
||||
<select
|
||||
@@ -118,8 +104,8 @@ export const ToolTypeEditorPanel = ({
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="row" style={{ gap: "1rem" }}>
|
||||
<div className="form-group" style={{ flex: 1 }}>
|
||||
<div className="form-row row-md">
|
||||
<div className="form-group">
|
||||
<label htmlFor="tool-type-name">Name *</label>
|
||||
<input
|
||||
id="tool-type-name"
|
||||
@@ -134,7 +120,7 @@ export const ToolTypeEditorPanel = ({
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group" style={{ flex: 1 }}>
|
||||
<div className="form-group">
|
||||
<label htmlFor="tool-type-display-name">
|
||||
Display Name *
|
||||
</label>
|
||||
@@ -166,8 +152,8 @@ export const ToolTypeEditorPanel = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="row" style={{ gap: "1rem" }}>
|
||||
<div className="form-group" style={{ flex: 1 }}>
|
||||
<div className="form-row row-md">
|
||||
<div className="form-group">
|
||||
<label htmlFor="tool-type-category">Category</label>
|
||||
<input
|
||||
id="tool-type-category"
|
||||
@@ -180,7 +166,7 @@ export const ToolTypeEditorPanel = ({
|
||||
className="form-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group" style={{ flex: 1 }}>
|
||||
<div className="form-group">
|
||||
<label htmlFor="tool-type-interface">Interface Type</label>
|
||||
<select
|
||||
id="tool-type-interface"
|
||||
@@ -280,11 +266,7 @@ export const ToolTypeEditorPanel = ({
|
||||
? "version: '3.8'\nservices:\n app:\n image: ..."
|
||||
: "FROM node:18\nWORKDIR /app\n..."
|
||||
}
|
||||
className="form-input"
|
||||
style={{
|
||||
fontFamily: "monospace",
|
||||
fontSize: "0.875rem",
|
||||
}}
|
||||
className="form-input font-mono text-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
@@ -306,8 +288,8 @@ export const ToolTypeEditorPanel = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="row" style={{ gap: "1rem" }}>
|
||||
<div className="form-group" style={{ flex: 1 }}>
|
||||
<div className="form-row row-md">
|
||||
<div className="form-group">
|
||||
<label htmlFor="readiness-timeout">Timeout (seconds)</label>
|
||||
<input
|
||||
id="readiness-timeout"
|
||||
@@ -319,7 +301,7 @@ export const ToolTypeEditorPanel = ({
|
||||
className="form-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group" style={{ flex: 1 }}>
|
||||
<div className="form-group">
|
||||
<label htmlFor="readiness-interval">
|
||||
Interval (seconds)
|
||||
</label>
|
||||
@@ -350,8 +332,8 @@ export const ToolTypeEditorPanel = ({
|
||||
|
||||
{toolTypeError && <p className="text-error">{toolTypeError}</p>}
|
||||
|
||||
<div className="dialog-actions" style={{ marginTop: "1rem" }}>
|
||||
<button type="submit">
|
||||
<div className="dialog-actions mt-4">
|
||||
<button type="submit" className="btn btn-primary">
|
||||
<Icon name={isCreating ? "add" : "save"} size="sm" />
|
||||
{isCreating ? "Create Tool Type" : "Save Changes"}
|
||||
</button>
|
||||
@@ -359,7 +341,7 @@ export const ToolTypeEditorPanel = ({
|
||||
<button
|
||||
type="button"
|
||||
onClick={onReset}
|
||||
className="button-secondary"
|
||||
className="btn btn-secondary"
|
||||
>
|
||||
<Icon name="cancel" size="sm" /> Discard
|
||||
</button>
|
||||
|
||||
@@ -17,82 +17,28 @@ export const ToolTypeListSidebar = ({
|
||||
onDelete,
|
||||
}: ToolTypeListSidebarProps) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: "280px",
|
||||
minWidth: "280px",
|
||||
borderRight: "1px solid var(--border)",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
background: "var(--panel)",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{ padding: "1rem", borderBottom: "1px solid var(--border)" }}
|
||||
>
|
||||
<h2 style={{ margin: 0, fontSize: "1.125rem" }}>Tool Workshop</h2>
|
||||
<p
|
||||
className="muted"
|
||||
style={{ margin: "0.25rem 0 0 0", fontSize: "0.875rem" }}
|
||||
>
|
||||
<div className="sidebar">
|
||||
<div className="sidebar-header">
|
||||
<h2>Tool Workshop</h2>
|
||||
<p className="muted">
|
||||
{toolTypes.length} tool type{toolTypes.length !== 1 ? "s" : ""}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style={{ flex: 1, overflowY: "auto", padding: "0.5rem" }}>
|
||||
<div className="sidebar-list">
|
||||
{toolTypes.map((toolType) => (
|
||||
<button
|
||||
key={toolType.id}
|
||||
onClick={() => onSelect(toolType)}
|
||||
style={{
|
||||
width: "100%",
|
||||
textAlign: "left",
|
||||
padding: "0.75rem 1rem",
|
||||
marginBottom: "0.25rem",
|
||||
borderRadius: "0.375rem",
|
||||
border: "none",
|
||||
background:
|
||||
selectedToolTypeId === toolType.id
|
||||
? "var(--brand)"
|
||||
: "transparent",
|
||||
color:
|
||||
selectedToolTypeId === toolType.id ? "white" : "var(--ink)",
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "0.75rem",
|
||||
transition: "background 0.15s",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (selectedToolTypeId !== toolType.id) {
|
||||
e.currentTarget.style.background = "#ece7df";
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (selectedToolTypeId !== toolType.id) {
|
||||
e.currentTarget.style.background = "transparent";
|
||||
}
|
||||
}}
|
||||
className={
|
||||
selectedToolTypeId === toolType.id
|
||||
? "sidebar-item sidebar-item-active"
|
||||
: "sidebar-item"
|
||||
}
|
||||
>
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
<div
|
||||
style={{
|
||||
fontWeight: 600,
|
||||
fontSize: "0.9375rem",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
}}
|
||||
>
|
||||
{toolType.display_name}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "0.8125rem",
|
||||
opacity: 0.8,
|
||||
marginTop: "0.125rem",
|
||||
}}
|
||||
>
|
||||
<div className="sidebar-item-content">
|
||||
<div className="sidebar-item-title">{toolType.display_name}</div>
|
||||
<div className="sidebar-item-subtitle">
|
||||
{toolType.category || "Uncategorized"} ·{" "}
|
||||
{toolType.interface_type === "web"
|
||||
? `Port ${toolType.default_port}`
|
||||
@@ -104,19 +50,6 @@ export const ToolTypeListSidebar = ({
|
||||
e.stopPropagation();
|
||||
onDelete(toolType.id);
|
||||
}}
|
||||
style={{
|
||||
background: "none",
|
||||
border: "none",
|
||||
color:
|
||||
selectedToolTypeId === toolType.id
|
||||
? "rgba(255,255,255,0.8)"
|
||||
: "var(--muted)",
|
||||
cursor: "pointer",
|
||||
padding: "0.25rem",
|
||||
borderRadius: "0.25rem",
|
||||
flexShrink: 0,
|
||||
opacity: 0,
|
||||
}}
|
||||
className="delete-btn"
|
||||
title="Delete tool type"
|
||||
>
|
||||
@@ -126,33 +59,8 @@ export const ToolTypeListSidebar = ({
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ padding: "1rem", borderTop: "1px solid var(--border)" }}>
|
||||
<button
|
||||
onClick={onCreate}
|
||||
style={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: "0.5rem",
|
||||
padding: "0.75rem",
|
||||
borderRadius: "0.5rem",
|
||||
border: "2px dashed var(--border)",
|
||||
background: "transparent",
|
||||
color: "var(--muted)",
|
||||
cursor: "pointer",
|
||||
fontWeight: 600,
|
||||
transition: "all 0.15s",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.borderColor = "var(--brand)";
|
||||
e.currentTarget.style.color = "var(--brand)";
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.borderColor = "var(--border)";
|
||||
e.currentTarget.style.color = "var(--muted)";
|
||||
}}
|
||||
>
|
||||
<div className="sidebar-footer">
|
||||
<button onClick={onCreate} className="sidebar-create-button">
|
||||
<Icon name="add" size="sm" /> New Tool Type
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user