chore: standardized form input components

This commit is contained in:
Aleix Soler 2025-07-16 18:49:21 +02:00
parent 9a638cdefb
commit f1b697b47a
5 changed files with 125 additions and 58 deletions

View file

@ -1,5 +1,6 @@
import React from "react";
import { SearchFilter } from "@/components/atoms/SearchFilter";
import { Input } from "@/components/atoms/Input";
interface FilterSectionProps {
searchFilter: string;
@ -23,12 +24,12 @@ export const FilterSection = ({
onFilterChange={onSearchFilterChange}
/>
<div className="grouped-status-note-filter">
<input
type="text"
<Input
variant="text"
value={noteNameFilter}
onChange={onNoteNameFilterChange}
placeholder="Filter by note name..."
className="grouped-status-note-input"
value={noteNameFilter}
onChange={(e) => onNoteNameFilterChange(e.target.value)}
/>
</div>
</div>

View file

@ -1,6 +1,7 @@
import { NoteStatus } from "@/types/noteStatus";
import { PluginSettings } from "@/types/pluginSettings";
import React from "react";
import { Input } from "@/components/atoms/Input";
export type Props = {
status: NoteStatus;
@ -26,56 +27,48 @@ export const CustomStatusItem: React.FC<Props> = ({
className="custom-status-preview"
style={{ borderLeftColor: status.color || "var(--text-muted)" }}
>
<input
className="custom-status-icon-input"
type="text"
placeholder="🔥"
<Input
variant="text"
value={status.icon}
onChange={(e) =>
onCustomStatusChange(
index,
"icon",
e.target.value || "❓",
)
onChange={(value) =>
onCustomStatusChange(index, "icon", value || "❓")
}
placeholder="🔥"
className="custom-status-icon-input"
/>
<div className="custom-status-text-inputs">
<input
className="custom-status-name-input"
type="text"
placeholder="Status name"
<Input
variant="text"
value={status.name}
onChange={(e) =>
onChange={(value) =>
onCustomStatusChange(
index,
"name",
e.target.value || "unnamed",
value || "unnamed",
)
}
placeholder="Status name"
className="custom-status-name-input"
style={{ color: status.color || "var(--text-normal)" }}
/>
<input
className="custom-status-description-input"
type="text"
placeholder="Description (optional)"
<Input
variant="text"
value={status.description || ""}
onChange={(e) =>
onCustomStatusChange(
index,
"description",
e.target.value,
)
onChange={(value) =>
onCustomStatusChange(index, "description", value)
}
placeholder="Description (optional)"
className="custom-status-description-input"
/>
</div>
<div className="custom-status-controls">
<input
className="custom-status-color-input"
type="color"
<Input
variant="color"
value={status.color || "#ffffff"}
onChange={(e) =>
onCustomStatusChange(index, "color", e.target.value)
onChange={(value) =>
onCustomStatusChange(index, "color", value)
}
className="custom-status-color-input"
/>
<button
className="custom-status-remove-btn clickable-icon mod-warning"

View file

@ -0,0 +1,78 @@
import React from "react";
export type InputVariant = "text" | "color" | "search";
interface BaseInputProps {
variant: InputVariant;
value: string;
onChange: (value: string) => void;
placeholder?: string;
className?: string;
style?: React.CSSProperties;
}
interface TextInputProps extends BaseInputProps {
variant: "text";
}
interface ColorInputProps extends BaseInputProps {
variant: "color";
}
interface SearchInputProps extends BaseInputProps {
variant: "search";
}
export type InputProps = TextInputProps | ColorInputProps | SearchInputProps;
const getInputStyles = (variant: InputVariant): React.CSSProperties => {
const baseStyles: React.CSSProperties = {
border: "1px solid var(--background-modifier-border)",
borderRadius: "4px",
backgroundColor: "var(--background-primary)",
color: "var(--text-normal)",
fontSize: "14px",
outline: "none",
};
switch (variant) {
case "text":
case "search":
return {
...baseStyles,
width: "100%",
padding: "8px 12px",
};
case "color":
return {
...baseStyles,
width: "32px",
height: "32px",
padding: "2px",
cursor: "pointer",
};
default:
return baseStyles;
}
};
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ variant, value, onChange, placeholder, className, style }, ref) => {
const inputStyles = getInputStyles(variant);
const combinedStyles = { ...inputStyles, ...style };
return (
<input
ref={ref}
type={variant === "color" ? "color" : "text"}
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
className={className}
style={combinedStyles}
/>
);
},
);
Input.displayName = "Input";

View file

@ -1,4 +1,5 @@
import React from "react";
import { Input } from "./Input";
interface Props {
value: string;
@ -9,21 +10,12 @@ interface Props {
export const SearchFilter = React.forwardRef<HTMLInputElement, Props>(
({ value, onFilterChange, placeholder = "Search..." }, ref) => {
return (
<input
<Input
ref={ref}
type="text"
variant="search"
value={value}
onChange={(e) => onFilterChange(e.target.value)}
onChange={onFilterChange}
placeholder={placeholder}
style={{
width: "100%",
padding: "8px 12px",
border: "1px solid var(--background-modifier-border)",
borderRadius: "4px",
backgroundColor: "var(--background-primary)",
color: "var(--text-normal)",
fontSize: "14px",
}}
/>
);
},

View file

@ -19,9 +19,9 @@
width: 40px;
text-align: center;
font-size: 1.2em;
background: transparent;
border: none;
padding: 2px;
background: transparent !important;
border: none !important;
padding: 2px !important;
}
.custom-status-text-inputs {
@ -29,21 +29,23 @@
}
.custom-status-name-input {
background: transparent;
border: none;
background: transparent !important;
border: none !important;
color: var(--text-normal);
font-weight: var(--font-semibold);
font-size: var(--font-ui-medium);
width: 100%;
width: 100% !important;
margin-bottom: 2px;
padding: 2px !important;
}
.custom-status-description-input {
background: transparent;
border: none;
background: transparent !important;
border: none !important;
color: var(--text-muted);
font-size: var(--font-ui-smaller);
width: 100%;
width: 100% !important;
padding: 2px !important;
}
.custom-status-controls {
@ -53,10 +55,11 @@
}
.custom-status-color-input {
width: 32px;
height: 32px;
width: 32px !important;
height: 32px !important;
border-radius: var(--radius-s);
cursor: pointer;
padding: 2px !important;
}
.custom-status-remove-btn {