mirror of
https://github.com/devonthesofa/obsidian-note-status.git
synced 2026-07-22 05:45:04 +00:00
feat: add configurable badge styles to status bar
This commit is contained in:
parent
c21f1eb5db
commit
5ddecab6ee
9 changed files with 97 additions and 9 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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: "",
|
||||
|
|
|
|||
|
|
@ -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={() => {
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue