mirror of
https://github.com/devonthesofa/obsidian-note-status.git
synced 2026-07-22 05:45:04 +00:00
chore: icon selection field added
This commit is contained in:
parent
e5233f6f0e
commit
2e7c3ad66c
4 changed files with 137 additions and 46 deletions
|
|
@ -2,7 +2,7 @@ import { NoteStatus } from "@/types/noteStatus";
|
|||
import React from "react";
|
||||
import { Input } from "@/components/atoms/Input";
|
||||
import { StatusIcon } from "@/components/atoms/StatusIcon";
|
||||
import { LucideIconPicker } from "./LucideIconPicker";
|
||||
import { IconSelectionField } from "./IconSelectionField";
|
||||
|
||||
export type Props = {
|
||||
status: NoteStatus;
|
||||
|
|
@ -32,44 +32,23 @@ export const CustomStatusItem: React.FC<Props> = ({
|
|||
const isValid = status.name.trim().length > 0;
|
||||
return (
|
||||
<div className="custom-status-item">
|
||||
<div className="custom-status-item__row custom-status-item__row--icons">
|
||||
<div className="custom-status-item__field custom-status-item__field--icon">
|
||||
<label className="custom-status-item__label">
|
||||
Emoji icon
|
||||
</label>
|
||||
<Input
|
||||
variant="text"
|
||||
value={status.icon}
|
||||
onChange={(value) =>
|
||||
onCustomStatusChange(index, "icon", value || "")
|
||||
}
|
||||
placeholder="Example: ✅ or 🚧"
|
||||
className="custom-status-item__input custom-status-item__input--icon"
|
||||
/>
|
||||
<p className="custom-status-item__hint">
|
||||
This fallback icon is shown anywhere Lucide is not
|
||||
available.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="custom-status-item__field custom-status-item__field--lucide">
|
||||
<label className="custom-status-item__label">
|
||||
Lucide icon (optional)
|
||||
</label>
|
||||
<LucideIconPicker
|
||||
value={status.lucideIcon || ""}
|
||||
onChange={(value) =>
|
||||
onCustomStatusChange(index, "lucideIcon", value)
|
||||
}
|
||||
placeholder="Browse Lucide icons"
|
||||
allowClear
|
||||
/>
|
||||
<p className="custom-status-item__hint">
|
||||
Matches Obsidian's toolbar icons so your status
|
||||
button blends in.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<IconSelectionField
|
||||
className="custom-status-item__icon-fields"
|
||||
emojiValue={status.icon}
|
||||
onEmojiChange={(value) =>
|
||||
onCustomStatusChange(index, "icon", value || "")
|
||||
}
|
||||
emojiLabel="Emoji icon"
|
||||
emojiPlaceholder="Example: ✅ or 🚧"
|
||||
emojiHint="Shown anywhere Lucide is not available."
|
||||
lucideValue={status.lucideIcon || ""}
|
||||
onLucideChange={(value) =>
|
||||
onCustomStatusChange(index, "lucideIcon", value)
|
||||
}
|
||||
lucideLabel="Lucide icon (optional)"
|
||||
lucidePlaceholder="Browse Lucide icons"
|
||||
lucideHint="Matches Obsidian's toolbar icons so your status button blends in."
|
||||
/>
|
||||
|
||||
{/* Simple horizontal layout with remaining inputs */}
|
||||
<div className="custom-status-item__row">
|
||||
|
|
|
|||
75
components/SettingsUI/IconSelectionField.tsx
Normal file
75
components/SettingsUI/IconSelectionField.tsx
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import React from "react";
|
||||
import { Input } from "@/components/atoms/Input";
|
||||
import { LucideIconPicker } from "./LucideIconPicker";
|
||||
|
||||
export interface IconSelectionFieldProps {
|
||||
className?: string;
|
||||
emojiValue: string;
|
||||
onEmojiChange: (value: string) => void;
|
||||
emojiLabel?: string;
|
||||
emojiPlaceholder?: string;
|
||||
emojiHint?: string;
|
||||
lucideValue?: string;
|
||||
onLucideChange?: (value: string) => void;
|
||||
lucideLabel?: string;
|
||||
lucidePlaceholder?: string;
|
||||
lucideHint?: string;
|
||||
lucideAllowClear?: boolean;
|
||||
}
|
||||
|
||||
export const IconSelectionField: React.FC<IconSelectionFieldProps> = ({
|
||||
className = "",
|
||||
emojiValue,
|
||||
onEmojiChange,
|
||||
emojiLabel = "Emoji fallback",
|
||||
emojiPlaceholder = "Example: ✅",
|
||||
emojiHint,
|
||||
lucideValue,
|
||||
onLucideChange,
|
||||
lucideLabel = "Lucide icon",
|
||||
lucidePlaceholder = "Choose Lucide icon",
|
||||
lucideHint,
|
||||
lucideAllowClear = true,
|
||||
}) => {
|
||||
const containerClass = ["icon-selection-field", className]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
return (
|
||||
<div className={containerClass}>
|
||||
<div className="icon-selection-field__column">
|
||||
<label className="icon-selection-field__label">
|
||||
{emojiLabel}
|
||||
</label>
|
||||
<Input
|
||||
variant="text"
|
||||
value={emojiValue}
|
||||
onChange={onEmojiChange}
|
||||
placeholder={emojiPlaceholder}
|
||||
className="icon-selection-field__emoji-input"
|
||||
/>
|
||||
{emojiHint && (
|
||||
<p className="icon-selection-field__hint">{emojiHint}</p>
|
||||
)}
|
||||
</div>
|
||||
{onLucideChange && (
|
||||
<div className="icon-selection-field__column">
|
||||
<label className="icon-selection-field__label">
|
||||
{lucideLabel}
|
||||
</label>
|
||||
<LucideIconPicker
|
||||
value={lucideValue}
|
||||
onChange={onLucideChange}
|
||||
placeholder={lucidePlaceholder}
|
||||
allowClear={lucideAllowClear}
|
||||
/>
|
||||
{lucideHint && (
|
||||
<p className="icon-selection-field__hint">
|
||||
{lucideHint}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -3,7 +3,7 @@ import React from "react";
|
|||
import { Input } from "../atoms/Input";
|
||||
import { Select } from "../atoms/Select";
|
||||
import { SettingItem } from "./SettingItem";
|
||||
import { LucideIconPicker } from "./LucideIconPicker";
|
||||
import { IconSelectionField } from "./IconSelectionField";
|
||||
|
||||
export type Props = {
|
||||
settings: PluginSettings;
|
||||
|
|
@ -270,13 +270,21 @@ export const UISettings: React.FC<Props> = ({ settings, onChange }) => {
|
|||
<SettingItem
|
||||
name="Icon for unknown status"
|
||||
description="Emoji or Lucide icon name displayed whenever a note does not have a status."
|
||||
vertical
|
||||
>
|
||||
<LucideIconPicker
|
||||
value={settings.unknownStatusIcon}
|
||||
onChange={(value) => onChange("unknownStatusIcon", value)}
|
||||
placeholder="Emoji or Lucide icon"
|
||||
allowTextInput
|
||||
allowClear
|
||||
<IconSelectionField
|
||||
emojiValue={settings.unknownStatusIcon}
|
||||
onEmojiChange={(value) =>
|
||||
onChange("unknownStatusIcon", value)
|
||||
}
|
||||
emojiPlaceholder="❓"
|
||||
emojiHint="Type any emoji or text fallback."
|
||||
lucideValue={settings.unknownStatusIcon}
|
||||
onLucideChange={(value) =>
|
||||
onChange("unknownStatusIcon", value)
|
||||
}
|
||||
lucidePlaceholder="Choose Lucide icon"
|
||||
lucideHint="Matches the Obsidian toolbar style."
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
|
|
|
|||
|
|
@ -155,3 +155,32 @@
|
|||
color: var(--text-muted);
|
||||
padding: var(--size-4-2);
|
||||
}
|
||||
|
||||
.icon-selection-field {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--size-4-2);
|
||||
}
|
||||
|
||||
.icon-selection-field__column {
|
||||
flex: 1;
|
||||
min-width: 220px;
|
||||
}
|
||||
|
||||
.icon-selection-field__label {
|
||||
display: block;
|
||||
font-size: var(--font-ui-smaller);
|
||||
font-weight: var(--font-medium);
|
||||
color: var(--text-muted);
|
||||
margin-bottom: var(--size-2-1);
|
||||
}
|
||||
|
||||
.icon-selection-field__emoji-input {
|
||||
max-width: 260px;
|
||||
}
|
||||
|
||||
.icon-selection-field__hint {
|
||||
margin-top: var(--size-2-1);
|
||||
font-size: var(--font-ui-smaller);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue