mirror of
https://github.com/devonthesofa/obsidian-note-status.git
synced 2026-07-22 12:30:24 +00:00
chore: standardized form input components
This commit is contained in:
parent
9a638cdefb
commit
f1b697b47a
5 changed files with 125 additions and 58 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
78
components/atoms/Input.tsx
Normal file
78
components/atoms/Input.tsx
Normal 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";
|
||||
|
|
@ -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",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue