feat: add configurable badge styles to status bar

This commit is contained in:
Aleix Soler 2025-11-22 11:23:07 +01:00
parent c21f1eb5db
commit 5ddecab6ee
9 changed files with 97 additions and 9 deletions

View file

@ -80,6 +80,21 @@ export const UISettings: React.FC<Props> = ({ settings, onChange }) => {
/>
</SettingItem>
<SettingItem
name="Status bar badge style"
description="Match the file explorer visuals: accent stripe, solid fill, or dot marker."
>
<Select
options={[
{ value: "accent", display: "Accent stripe (default)" },
{ value: "filled", display: "Solid background" },
{ value: "dot", display: "Dot marker" },
]}
defaultValue={settings.statusBarBadgeStyle || "accent"}
onChange={(value) => onChange("statusBarBadgeStyle", value)}
/>
</SettingItem>
<h4>No Status Display</h4>
<SettingItem

View file

@ -13,6 +13,7 @@ export type Props = {
hideIfNotStatuses?: boolean;
onStatusClick: StatusBarContextProps["onStatusClick"];
templateNameMode?: "always" | "never" | "auto";
badgeStyle?: "accent" | "filled" | "dot";
noStatusConfig?: {
text: string;
showIcon: boolean;
@ -28,6 +29,7 @@ export const StatusBar: FC<Props> = ({
hideIfNotStatuses,
onStatusClick,
templateNameMode = "auto",
badgeStyle = "accent",
noStatusConfig,
}) => {
const statusEntries = Object.entries(statuses);
@ -80,6 +82,7 @@ export const StatusBar: FC<Props> = ({
key={frontmatterTagName}
statuses={statusList}
templateNameMode={templateNameMode}
badgeStyle={badgeStyle}
template={{
description: "Note status",
name: "",

View file

@ -11,6 +11,7 @@ export interface StatusBarGroupProps {
template: StatusTemplate;
maxVisible?: number;
templateNameMode?: "always" | "never" | "auto";
badgeStyle?: "accent" | "filled" | "dot";
}
export const StatusBarGroup: FC<StatusBarGroupProps> = ({
@ -18,6 +19,7 @@ export const StatusBarGroup: FC<StatusBarGroupProps> = ({
template,
maxVisible = 3,
templateNameMode = "auto",
badgeStyle = "accent",
}) => {
const [isUncollapsed, setIsUncollapsed] = useState(false);
const visibleStatuses = isUncollapsed
@ -52,6 +54,7 @@ export const StatusBarGroup: FC<StatusBarGroupProps> = ({
<StatusDisplay
status={status}
variant="badge"
badgeStyle={badgeStyle}
templateNameMode={templateNameMode}
hasNameConflicts={getHasConflicts(status)}
onClick={() => {

View file

@ -17,6 +17,7 @@ export type StatusDisplayVariant = "chip" | "badge" | "template";
interface StatusDisplayProps {
status: NoteStatus;
variant: StatusDisplayVariant;
badgeStyle?: "accent" | "filled" | "dot";
removable?: boolean;
hasNameConflicts?: boolean;
templateNameMode?: "always" | "never" | "auto";
@ -30,6 +31,7 @@ export const StatusDisplay: FC<StatusDisplayProps> = memo(
status,
variant,
removable = false,
badgeStyle = "accent",
hasNameConflicts = false,
templateNameMode = "auto",
icon,
@ -121,19 +123,30 @@ export const StatusDisplay: FC<StatusDisplayProps> = memo(
}
if (variant === "badge") {
const badgeStyle = status.color
const badgeStyleVars = status.color
? ({
"--status-accent": status.color,
} as CSSProperties)
: undefined;
const badgeClassName = [
"status-badge-container",
`status-badge--${badgeStyle}`,
onClick ? "status-badge-container--clickable" : "",
]
.filter(Boolean)
.join(" ");
const showDot = badgeStyle === "dot";
return (
<div
className={`status-badge-container${onClick ? " status-badge-container--clickable" : ""}`}
style={badgeStyle}
className={badgeClassName}
style={badgeStyleVars}
onClick={handleClick}
data-clickable={!!onClick}
>
{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">

View file

@ -45,6 +45,7 @@ export const DEFAULT_PLUGIN_SETTINGS: PluginSettings = {
statusBarNoStatusText: "No status",
statusBarShowNoStatusIcon: false,
statusBarShowNoStatusText: true,
statusBarBadgeStyle: "accent",
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

@ -154,6 +154,7 @@ export class StatusBarIntegration {
templateNameMode={
settingsService.settings.statusBarShowTemplateName
}
badgeStyle={settingsService.settings.statusBarBadgeStyle}
onStatusClick={() => this.openStatusModal()}
noStatusConfig={this.getNoStatusConfig()}
/>,

File diff suppressed because one or more lines are too long

View file

@ -74,9 +74,8 @@
align-items: center;
gap: var(--size-2-2);
padding: var(--size-2-1) var(--size-4-2);
padding-left: calc(var(--size-4-1) + 4px);
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-s);
border: 1px solid var(--background-modifier-border);
background: var(--background-primary);
position: relative;
overflow: hidden;
@ -88,22 +87,74 @@
position: absolute;
inset: 0 auto 0 0;
width: 4px;
background: var(--status-accent, var(--interactive-accent));
background: transparent;
opacity: 0.85;
display: none;
}
.status-badge-container--clickable {
cursor: pointer;
transition:
background var(--anim-duration-fast) ease,
box-shadow var(--anim-duration-fast) ease;
box-shadow var(--anim-duration-fast) ease,
filter var(--anim-duration-fast) ease;
}
.status-badge-container--clickable:hover {
.status-badge-container--clickable:not(.status-badge--filled):hover {
background: var(--background-modifier-hover);
box-shadow: var(--shadow-s);
}
.status-badge--accent {
padding-left: calc(var(--size-4-1) + 4px);
}
.status-badge--accent::before {
display: block;
background: var(--status-accent, var(--interactive-accent));
}
.status-badge--filled {
background: var(--status-accent, var(--interactive-accent));
border-color: var(--status-accent, var(--interactive-accent));
color: var(--text-on-accent);
padding-left: var(--size-4-2);
}
.status-badge--filled .status-badge-icon,
.status-badge--filled .status-badge-text {
color: inherit;
}
.status-badge--filled.status-badge-container--clickable:hover {
filter: brightness(1.05);
background: var(--status-accent, var(--interactive-accent));
box-shadow: var(--shadow-s);
}
.status-badge--dot {
border: none;
background: transparent;
padding: var(--size-2-1) var(--size-2-2);
gap: var(--size-2-1);
}
.status-badge--dot::before {
display: none;
}
.status-badge--dot .status-badge-item {
gap: var(--size-2-2);
}
.status-badge-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--status-accent, var(--interactive-accent));
box-shadow: 0 0 0 1px var(--background-primary);
}
.status-badge-item {
display: flex;
align-items: center;

View file

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