feat: make status bar badges reactive and add content modes

This commit is contained in:
Aleix Soler 2025-11-22 11:32:02 +01:00
parent 5ddecab6ee
commit 6c4dcbc293
9 changed files with 77 additions and 5 deletions

View file

@ -95,6 +95,29 @@ export const UISettings: React.FC<Props> = ({ settings, onChange }) => {
/>
</SettingItem>
<SettingItem
name="Status bar badge content"
description="Choose whether the badge shows icon, text, both, or an empty accent."
>
<Select
options={[
{
value: "icon-text",
display: "Icon + text (default)",
},
{ value: "icon", display: "Icon only" },
{ value: "text", display: "Text only" },
{ value: "none", display: "Empty badge (accent only)" },
]}
defaultValue={
settings.statusBarBadgeContentMode || "icon-text"
}
onChange={(value) =>
onChange("statusBarBadgeContentMode", value)
}
/>
</SettingItem>
<h4>No Status Display</h4>
<SettingItem

View file

@ -14,6 +14,7 @@ export type Props = {
onStatusClick: StatusBarContextProps["onStatusClick"];
templateNameMode?: "always" | "never" | "auto";
badgeStyle?: "accent" | "filled" | "dot";
badgeContentMode?: "icon-text" | "icon" | "text" | "none";
noStatusConfig?: {
text: string;
showIcon: boolean;
@ -30,6 +31,7 @@ export const StatusBar: FC<Props> = ({
onStatusClick,
templateNameMode = "auto",
badgeStyle = "accent",
badgeContentMode = "icon-text",
noStatusConfig,
}) => {
const statusEntries = Object.entries(statuses);
@ -83,6 +85,7 @@ export const StatusBar: FC<Props> = ({
statuses={statusList}
templateNameMode={templateNameMode}
badgeStyle={badgeStyle}
badgeContentMode={badgeContentMode}
template={{
description: "Note status",
name: "",

View file

@ -12,6 +12,7 @@ export interface StatusBarGroupProps {
maxVisible?: number;
templateNameMode?: "always" | "never" | "auto";
badgeStyle?: "accent" | "filled" | "dot";
badgeContentMode?: "icon-text" | "icon" | "text" | "none";
}
export const StatusBarGroup: FC<StatusBarGroupProps> = ({
@ -20,6 +21,7 @@ export const StatusBarGroup: FC<StatusBarGroupProps> = ({
maxVisible = 3,
templateNameMode = "auto",
badgeStyle = "accent",
badgeContentMode = "icon-text",
}) => {
const [isUncollapsed, setIsUncollapsed] = useState(false);
const visibleStatuses = isUncollapsed
@ -55,6 +57,7 @@ export const StatusBarGroup: FC<StatusBarGroupProps> = ({
status={status}
variant="badge"
badgeStyle={badgeStyle}
badgeContentMode={badgeContentMode}
templateNameMode={templateNameMode}
hasNameConflicts={getHasConflicts(status)}
onClick={() => {

View file

@ -18,6 +18,7 @@ interface StatusDisplayProps {
status: NoteStatus;
variant: StatusDisplayVariant;
badgeStyle?: "accent" | "filled" | "dot";
badgeContentMode?: "icon-text" | "icon" | "text" | "none";
removable?: boolean;
hasNameConflicts?: boolean;
templateNameMode?: "always" | "never" | "auto";
@ -32,6 +33,7 @@ export const StatusDisplay: FC<StatusDisplayProps> = memo(
variant,
removable = false,
badgeStyle = "accent",
badgeContentMode = "icon-text",
hasNameConflicts = false,
templateNameMode = "auto",
icon,
@ -132,10 +134,16 @@ export const StatusDisplay: FC<StatusDisplayProps> = memo(
"status-badge-container",
`status-badge--${badgeStyle}`,
onClick ? "status-badge-container--clickable" : "",
badgeContentMode === "none" ? "status-badge--empty" : "",
]
.filter(Boolean)
.join(" ");
const showDot = badgeStyle === "dot";
const showIcon =
badgeContentMode === "icon-text" || badgeContentMode === "icon";
const showText =
badgeContentMode === "icon-text" || badgeContentMode === "text";
const isEmptyBadge = badgeContentMode === "none";
return (
<div
@ -143,15 +151,28 @@ export const StatusDisplay: FC<StatusDisplayProps> = memo(
style={badgeStyleVars}
onClick={handleClick}
data-clickable={!!onClick}
title={getStatusTooltip(status)}
>
{showDot && (
<span className="status-badge-dot" aria-hidden="true" />
)}
<div className="status-badge-item">
<span className="status-badge-icon">{iconNode}</span>
<span className="status-badge-text">
{getDisplayName()}
</span>
{showIcon && (
<span className="status-badge-icon">
{iconNode}
</span>
)}
{showText && (
<span className="status-badge-text">
{getDisplayName()}
</span>
)}
{isEmptyBadge && (
<span
className="status-badge-empty"
aria-hidden="true"
/>
)}
</div>
</div>
);

View file

@ -46,6 +46,7 @@ export const DEFAULT_PLUGIN_SETTINGS: PluginSettings = {
statusBarShowNoStatusIcon: false,
statusBarShowNoStatusText: true,
statusBarBadgeStyle: "accent",
statusBarBadgeContentMode: "icon-text",
vaultSizeLimit: 15000, // Disable dashboard and grouped view for vaults with more notes than this limit
// Editor toolbar button settings
showEditorToolbarButton: true, // Default to show the toolbar button

View file

@ -38,6 +38,12 @@ export class StatusBarIntegration {
if (key === "statusBarShowTemplateName") {
this.render(); // INFO: Force a render to set disabled or enabled
}
if (
key === "statusBarBadgeStyle" ||
key === "statusBarBadgeContentMode"
) {
this.render();
}
if (key === "enabledTemplates" || key === "templates") {
this.handleActiveFileChange().catch(console.error); // INFO: Force a re-read of the statuses and render
}
@ -155,6 +161,9 @@ export class StatusBarIntegration {
settingsService.settings.statusBarShowTemplateName
}
badgeStyle={settingsService.settings.statusBarBadgeStyle}
badgeContentMode={
settingsService.settings.statusBarBadgeContentMode
}
onStatusClick={() => this.openStatusModal()}
noStatusConfig={this.getNoStatusConfig()}
/>,

File diff suppressed because one or more lines are too long

View file

@ -155,6 +155,11 @@
box-shadow: 0 0 0 1px var(--background-primary);
}
.status-badge--empty {
min-width: 32px;
justify-content: center;
}
.status-badge-item {
display: flex;
align-items: center;
@ -172,6 +177,12 @@
font-size: var(--font-ui-small);
}
.status-badge-empty {
display: inline-block;
min-width: var(--size-3-2);
height: var(--size-3-2);
}
/* Template variant */
.template-status-chip {
display: inline-flex;

View file

@ -37,6 +37,7 @@ export type PluginSettings = {
customStatuses: NoteStatus[];
statusBarShowTemplateName: "always" | "never" | "auto"; // How to show template names in status bar
statusBarBadgeStyle: "accent" | "filled" | "dot";
statusBarBadgeContentMode: "icon-text" | "icon" | "text" | "none";
showStatusIconsInExplorer: boolean;
hideUnknownStatusInExplorer: boolean;
fileExplorerColorFileName: boolean; // Whether to color the file explorer filename text using the current status color