refactor(ui): replace inline INPUT_CLS/LABEL_CLS/BTN_DANGER constants and action link classes with CSS component classes
Remove duplicated Tailwind class string constants from 15 component files. Use app-input, app-select, app-label, app-action-danger-btn, and app-action-delete CSS component classes from globals.css instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,8 +18,6 @@ import type { CatalogField } from "~/lib/blueprint-field-catalog.js";
|
||||
// Styles
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const INPUT_CLS = "app-input";
|
||||
|
||||
const BTN_PRIMARY =
|
||||
"px-4 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 text-sm font-medium disabled:opacity-50";
|
||||
|
||||
@@ -496,7 +494,7 @@ export function BlueprintFieldCatalog({
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder="Search fields..."
|
||||
className={`${INPUT_CLS} w-full`}
|
||||
className="app-input"
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
@@ -636,7 +634,7 @@ export function BlueprintFieldCatalog({
|
||||
)
|
||||
}
|
||||
placeholder="field_key"
|
||||
className={`${INPUT_CLS} font-mono`}
|
||||
className="app-input font-mono"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
@@ -651,7 +649,7 @@ export function BlueprintFieldCatalog({
|
||||
setCustomLabel(e.target.value)
|
||||
}
|
||||
placeholder="Display Label"
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
@@ -665,7 +663,7 @@ export function BlueprintFieldCatalog({
|
||||
e.target.value as FieldType,
|
||||
)
|
||||
}
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
>
|
||||
{FIELD_TYPES.map((ft) => (
|
||||
<option key={ft.value} value={ft.value}>
|
||||
|
||||
@@ -18,16 +18,12 @@ const FIELD_TYPES: { value: FieldType; label: string }[] = [
|
||||
{ value: FieldType.EMAIL, label: "Email" },
|
||||
];
|
||||
|
||||
const INPUT_CLS = "app-input";
|
||||
|
||||
const BTN_PRIMARY =
|
||||
"px-4 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 text-sm font-medium disabled:opacity-50";
|
||||
|
||||
const BTN_SECONDARY =
|
||||
"px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 text-sm font-medium";
|
||||
|
||||
const BTN_DANGER = "app-action-danger-btn";
|
||||
|
||||
function makeEmptyField(order: number): BlueprintFieldDefinition {
|
||||
return {
|
||||
id: Math.random().toString(36).slice(2),
|
||||
@@ -73,19 +69,19 @@ function OptionsEditor({ options, onChange }: OptionsEditorProps) {
|
||||
value={opt.value}
|
||||
onChange={(e) => updateOption(idx, "value", e.target.value)}
|
||||
placeholder="value"
|
||||
className={`${INPUT_CLS} flex-1`}
|
||||
className="app-input flex-1"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={opt.label}
|
||||
onChange={(e) => updateOption(idx, "label", e.target.value)}
|
||||
placeholder="label"
|
||||
className={`${INPUT_CLS} flex-1`}
|
||||
className="app-input flex-1"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeOption(idx)}
|
||||
className={BTN_DANGER}
|
||||
className="app-action-danger-btn"
|
||||
aria-label="Remove option"
|
||||
>
|
||||
×
|
||||
@@ -140,7 +136,7 @@ function FieldRow({ field, onChange, onDelete }: FieldRowProps) {
|
||||
value={field.key}
|
||||
onChange={(e) => update("key", e.target.value)}
|
||||
placeholder="field_key"
|
||||
className={`${INPUT_CLS} w-36 font-mono`}
|
||||
className="app-input w-36 font-mono"
|
||||
aria-label="Field key"
|
||||
/>
|
||||
|
||||
@@ -150,7 +146,7 @@ function FieldRow({ field, onChange, onDelete }: FieldRowProps) {
|
||||
value={field.label}
|
||||
onChange={(e) => update("label", e.target.value)}
|
||||
placeholder="Label"
|
||||
className={`${INPUT_CLS} w-40`}
|
||||
className="app-input w-40"
|
||||
aria-label="Field label"
|
||||
/>
|
||||
|
||||
@@ -166,7 +162,7 @@ function FieldRow({ field, onChange, onDelete }: FieldRowProps) {
|
||||
: undefined;
|
||||
onChange({ ...field, type: t, options: clearedOptions } as BlueprintFieldDefinition);
|
||||
}}
|
||||
className={`${INPUT_CLS} w-36`}
|
||||
className="app-input w-36"
|
||||
aria-label="Field type"
|
||||
>
|
||||
{FIELD_TYPES.map((ft) => (
|
||||
@@ -201,7 +197,7 @@ function FieldRow({ field, onChange, onDelete }: FieldRowProps) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={onDelete}
|
||||
className={BTN_DANGER}
|
||||
className="app-action-danger-btn"
|
||||
aria-label="Delete field"
|
||||
>
|
||||
×
|
||||
@@ -218,7 +214,7 @@ function FieldRow({ field, onChange, onDelete }: FieldRowProps) {
|
||||
value={field.group ?? ""}
|
||||
onChange={(e) => update("group", e.target.value || undefined)}
|
||||
placeholder="Section heading"
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
@@ -232,7 +228,7 @@ function FieldRow({ field, onChange, onDelete }: FieldRowProps) {
|
||||
update("placeholder", e.target.value || undefined)
|
||||
}
|
||||
placeholder="Placeholder text"
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
@@ -246,7 +242,7 @@ function FieldRow({ field, onChange, onDelete }: FieldRowProps) {
|
||||
update("description", e.target.value || undefined)
|
||||
}
|
||||
placeholder="Helper text"
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@ import { SortableColumnHeader } from "~/components/ui/SortableColumnHeader.js";
|
||||
import { useTableSort } from "~/hooks/useTableSort.js";
|
||||
import { useViewPrefs } from "~/hooks/useViewPrefs.js";
|
||||
|
||||
const INPUT_CLS = "app-input";
|
||||
|
||||
const BTN_PRIMARY =
|
||||
"px-4 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 text-sm font-medium disabled:opacity-50";
|
||||
|
||||
@@ -75,15 +73,15 @@ function NewBlueprintModal({ onClose, onCreated }: NewBlueprintModalProps) {
|
||||
<form onSubmit={handleSubmit} className="px-6 py-5 space-y-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-sm font-medium text-gray-700">Name <span className="text-red-500">*</span></label>
|
||||
<input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="e.g. Resource Extended Fields" className={INPUT_CLS} autoFocus />
|
||||
<input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="e.g. Resource Extended Fields" className="app-input" autoFocus />
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-sm font-medium text-gray-700">Description</label>
|
||||
<textarea value={description} onChange={(e) => setDescription(e.target.value)} placeholder="Optional description" className={`${INPUT_CLS} resize-none`} rows={2} />
|
||||
<textarea value={description} onChange={(e) => setDescription(e.target.value)} placeholder="Optional description" className="app-input resize-none" rows={2} />
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-sm font-medium text-gray-700">Target</label>
|
||||
<select value={target} onChange={(e) => setTarget(e.target.value as BlueprintTargetValue)} className={INPUT_CLS}>
|
||||
<select value={target} onChange={(e) => setTarget(e.target.value as BlueprintTargetValue)} className="app-input">
|
||||
<option value="RESOURCE">Resource</option>
|
||||
<option value="PROJECT">Project</option>
|
||||
</select>
|
||||
|
||||
@@ -59,8 +59,6 @@ interface FieldCardProps {
|
||||
// Component
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const INPUT_CLS = "app-input";
|
||||
|
||||
export function FieldCard({ field, overrides, onChange }: FieldCardProps) {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
@@ -193,7 +191,7 @@ export function FieldCard({ field, overrides, onChange }: FieldCardProps) {
|
||||
value={overrides.description}
|
||||
onChange={(e) => update({ description: e.target.value })}
|
||||
placeholder={field.description}
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -240,7 +238,7 @@ function DefaultValueInput({
|
||||
onChange(e.target.value === "" ? undefined : Number(e.target.value))
|
||||
}
|
||||
placeholder="No default"
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -252,7 +250,7 @@ function DefaultValueInput({
|
||||
onChange={(e) =>
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -263,7 +261,7 @@ function DefaultValueInput({
|
||||
onChange={(e) =>
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
>
|
||||
<option value="">No default</option>
|
||||
{(options ?? []).map((opt) => (
|
||||
@@ -292,7 +290,7 @@ function DefaultValueInput({
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
placeholder="https://..."
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -305,7 +303,7 @@ function DefaultValueInput({
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
placeholder="name@example.com"
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -317,7 +315,7 @@ function DefaultValueInput({
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
placeholder="No default"
|
||||
className={`${INPUT_CLS} resize-none`}
|
||||
className="app-input resize-none"
|
||||
rows={2}
|
||||
/>
|
||||
);
|
||||
@@ -331,7 +329,7 @@ function DefaultValueInput({
|
||||
onChange(e.target.value === "" ? undefined : e.target.value)
|
||||
}
|
||||
placeholder="No default"
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@ import { useState } from "react";
|
||||
import type { StaffingRequirement } from "@capakraken/shared";
|
||||
import { uuid } from "~/lib/uuid.js";
|
||||
|
||||
const INPUT_CLS = "app-input";
|
||||
const BTN_DANGER = "app-action-danger-btn";
|
||||
|
||||
function makeEmptyPreset(): StaffingRequirement {
|
||||
return {
|
||||
id: uuid(),
|
||||
@@ -38,7 +35,7 @@ function PresetRow({ preset, onChange, onDelete }: PresetRowProps) {
|
||||
value={preset.role}
|
||||
onChange={(e) => update("role", e.target.value)}
|
||||
placeholder="Role name"
|
||||
className={`${INPUT_CLS} flex-1 min-w-32`}
|
||||
className="app-input flex-1 min-w-32"
|
||||
aria-label="Role name"
|
||||
/>
|
||||
|
||||
@@ -58,7 +55,7 @@ function PresetRow({ preset, onChange, onDelete }: PresetRowProps) {
|
||||
)
|
||||
}
|
||||
placeholder="e.g. 3D Modeling, Lighting"
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
aria-label="Required skills"
|
||||
/>
|
||||
</div>
|
||||
@@ -73,7 +70,7 @@ function PresetRow({ preset, onChange, onDelete }: PresetRowProps) {
|
||||
max={24}
|
||||
step={0.5}
|
||||
onChange={(e) => update("hoursPerDay", parseFloat(e.target.value) || 0)}
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
aria-label="Hours per day"
|
||||
/>
|
||||
</div>
|
||||
@@ -87,7 +84,7 @@ function PresetRow({ preset, onChange, onDelete }: PresetRowProps) {
|
||||
min={1}
|
||||
max={20}
|
||||
onChange={(e) => update("headcount", parseInt(e.target.value, 10) || 1)}
|
||||
className={INPUT_CLS}
|
||||
className="app-input"
|
||||
aria-label="Headcount"
|
||||
/>
|
||||
</div>
|
||||
@@ -96,7 +93,7 @@ function PresetRow({ preset, onChange, onDelete }: PresetRowProps) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={onDelete}
|
||||
className={`${BTN_DANGER} self-end mb-0.5`}
|
||||
className="app-action-danger-btn self-end mb-0.5"
|
||||
aria-label="Remove preset"
|
||||
>
|
||||
×
|
||||
@@ -119,7 +116,7 @@ function PresetRow({ preset, onChange, onDelete }: PresetRowProps) {
|
||||
)
|
||||
}
|
||||
placeholder="e.g. Compositing, Art Direction"
|
||||
className={`${INPUT_CLS} w-full mt-0.5`}
|
||||
className="app-input mt-0.5"
|
||||
aria-label="Preferred skills"
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user