mirror of
https://github.com/devonthesofa/obsidian-note-status.git
synced 2026-07-22 12:30:24 +00:00
feat: multiple visual styles
This commit is contained in:
parent
48945b3d63
commit
7bb982ce2c
6 changed files with 215 additions and 51 deletions
|
|
@ -247,6 +247,41 @@ export const UISettings: React.FC<Props> = ({ settings, onChange }) => {
|
|||
/>
|
||||
</SettingItem>
|
||||
|
||||
<h4>Additional status visualization in file explorer</h4>
|
||||
|
||||
<SettingItem
|
||||
name="Show colored left border"
|
||||
description="Render a subtle colored strip on the left edge of the file explorer item."
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={settings.fileExplorerLeftBorder || false}
|
||||
onChange={handleChange("fileExplorerLeftBorder")}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
name="Show colored status dot"
|
||||
description="Append a compact colored dot next to the filename as an extra status indicator."
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={settings.fileExplorerStatusDot || false}
|
||||
onChange={handleChange("fileExplorerStatusDot")}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
name="Underline filename with status color"
|
||||
description="Adds a colored underline below the filename without changing the text color."
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={settings.fileExplorerUnderlineFileName || false}
|
||||
onChange={handleChange("fileExplorerUnderlineFileName")}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
name="Status icon frame"
|
||||
description="Choose whether to display a frame around the status icon inside the file explorer."
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ export const DEFAULT_PLUGIN_SETTINGS: PluginSettings = {
|
|||
hideUnknownStatusInExplorer: true, // Default to hide unknown status
|
||||
fileExplorerColorFileName: false,
|
||||
fileExplorerColorBlock: false,
|
||||
fileExplorerLeftBorder: false,
|
||||
fileExplorerStatusDot: false,
|
||||
fileExplorerUnderlineFileName: false,
|
||||
enabledTemplates: DEFAULT_ENABLED_TEMPLATES,
|
||||
useCustomStatusesOnly: false,
|
||||
useMultipleStatuses: true,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@ export class FileExplorerIntegration implements IElementProcessor {
|
|||
private readonly FILE_NAME_ORIGINAL_COLOR_ATTR = "noteStatusOriginalColor";
|
||||
private readonly FILE_BLOCK_CLASS = "note-status-colored-block";
|
||||
private readonly FILE_BLOCK_COLOR_VAR = "--note-status-block-color";
|
||||
private readonly FILE_BORDER_CLASS = "note-status-border-left";
|
||||
private readonly FILE_BORDER_COLOR_VAR = "--note-status-border-color";
|
||||
private readonly FILE_UNDERLINE_CLASS = "note-status-underline";
|
||||
private readonly FILE_UNDERLINE_COLOR_VAR = "--note-status-underline-color";
|
||||
private readonly STATUS_DOT_CLASS = "note-status-dot-badge";
|
||||
|
||||
constructor(plugin: Plugin) {
|
||||
this.plugin = plugin;
|
||||
|
|
@ -69,6 +74,9 @@ export class FileExplorerIntegration implements IElementProcessor {
|
|||
key === "fileExplorerIconColorMode" ||
|
||||
key === "fileExplorerColorFileName" ||
|
||||
key === "fileExplorerColorBlock" ||
|
||||
key === "fileExplorerLeftBorder" ||
|
||||
key === "fileExplorerStatusDot" ||
|
||||
key === "fileExplorerUnderlineFileName" ||
|
||||
key === "unknownStatusIcon" ||
|
||||
key === "unknownStatusLucideIcon" ||
|
||||
key === "unknownStatusColor" ||
|
||||
|
|
@ -112,21 +120,24 @@ export class FileExplorerIntegration implements IElementProcessor {
|
|||
}
|
||||
|
||||
const noteStatusService = this.getFileNoteStatusService(dataPath);
|
||||
const statuses = noteStatusService?.statuses ?? null;
|
||||
const primaryStatus = getPrimaryStatus(statuses);
|
||||
const hasStatus = Boolean(primaryStatus);
|
||||
const fallbackColor = getUnknownStatusColor();
|
||||
const statusColor = primaryStatus
|
||||
? resolveStatusColor(primaryStatus, fallbackColor)
|
||||
: undefined;
|
||||
const textElement = textEl as HTMLElement;
|
||||
const navItem = this.getNavItemElement(textElement);
|
||||
|
||||
this.applyFileNameColor(textElement, statusColor, hasStatus);
|
||||
this.applyFileNameUnderline(textElement, statusColor, hasStatus);
|
||||
this.applyStatusDot(textElement, statusColor, hasStatus);
|
||||
this.applyFileBlockColor(navItem, statusColor, hasStatus);
|
||||
this.applyLeftBorder(navItem, statusColor, hasStatus);
|
||||
|
||||
// Only render icons for markdown files
|
||||
if (noteStatusService) {
|
||||
this.applyFileNameColor(
|
||||
textEl as HTMLElement,
|
||||
noteStatusService.statuses,
|
||||
);
|
||||
this.applyFileBlockColor(
|
||||
textEl as HTMLElement,
|
||||
noteStatusService.statuses,
|
||||
);
|
||||
this.render(textEl, noteStatusService.statuses);
|
||||
} else {
|
||||
this.applyFileNameColor(textEl as HTMLElement, null);
|
||||
this.applyFileBlockColor(textEl as HTMLElement, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -294,28 +305,18 @@ export class FileExplorerIntegration implements IElementProcessor {
|
|||
|
||||
private applyFileNameColor(
|
||||
element?: HTMLElement | null,
|
||||
statuses?: GroupedStatuses | null,
|
||||
color?: string,
|
||||
hasStatus?: boolean,
|
||||
): void {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!settingsService.settings.fileExplorerColorFileName) {
|
||||
this.clearFileNameColor(element);
|
||||
return;
|
||||
}
|
||||
|
||||
const primaryStatus = getPrimaryStatus(statuses);
|
||||
if (!primaryStatus) {
|
||||
this.clearFileNameColor(element);
|
||||
return;
|
||||
}
|
||||
|
||||
const color = resolveStatusColor(
|
||||
primaryStatus,
|
||||
getUnknownStatusColor(),
|
||||
);
|
||||
if (!color) {
|
||||
if (
|
||||
!settingsService.settings.fileExplorerColorFileName ||
|
||||
!hasStatus ||
|
||||
!color
|
||||
) {
|
||||
this.clearFileNameColor(element);
|
||||
return;
|
||||
}
|
||||
|
|
@ -330,30 +331,19 @@ export class FileExplorerIntegration implements IElementProcessor {
|
|||
}
|
||||
|
||||
private applyFileBlockColor(
|
||||
element?: HTMLElement | null,
|
||||
statuses?: GroupedStatuses | null,
|
||||
navItem?: HTMLElement | null,
|
||||
color?: string,
|
||||
hasStatus?: boolean,
|
||||
): void {
|
||||
const navItem = this.getNavItemElement(element);
|
||||
if (!navItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!settingsService.settings.fileExplorerColorBlock) {
|
||||
this.clearFileBlockColor(navItem);
|
||||
return;
|
||||
}
|
||||
|
||||
const primaryStatus = getPrimaryStatus(statuses);
|
||||
if (!primaryStatus) {
|
||||
this.clearFileBlockColor(navItem);
|
||||
return;
|
||||
}
|
||||
|
||||
const color = resolveStatusColor(
|
||||
primaryStatus,
|
||||
getUnknownStatusColor(),
|
||||
);
|
||||
if (!color) {
|
||||
if (
|
||||
!settingsService.settings.fileExplorerColorBlock ||
|
||||
!hasStatus ||
|
||||
!color
|
||||
) {
|
||||
this.clearFileBlockColor(navItem);
|
||||
return;
|
||||
}
|
||||
|
|
@ -362,6 +352,87 @@ export class FileExplorerIntegration implements IElementProcessor {
|
|||
navItem.style.setProperty(this.FILE_BLOCK_COLOR_VAR, color);
|
||||
}
|
||||
|
||||
private applyLeftBorder(
|
||||
navItem?: HTMLElement | null,
|
||||
color?: string,
|
||||
hasStatus?: boolean,
|
||||
): void {
|
||||
if (!navItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!settingsService.settings.fileExplorerLeftBorder ||
|
||||
!hasStatus ||
|
||||
!color
|
||||
) {
|
||||
this.clearFileLeftBorder(navItem);
|
||||
return;
|
||||
}
|
||||
|
||||
navItem.classList.add(this.FILE_BORDER_CLASS);
|
||||
navItem.style.setProperty(this.FILE_BORDER_COLOR_VAR, color);
|
||||
}
|
||||
|
||||
private applyFileNameUnderline(
|
||||
element?: HTMLElement | null,
|
||||
color?: string,
|
||||
hasStatus?: boolean,
|
||||
): void {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!settingsService.settings.fileExplorerUnderlineFileName ||
|
||||
!hasStatus ||
|
||||
!color
|
||||
) {
|
||||
this.clearFileNameUnderline(element);
|
||||
return;
|
||||
}
|
||||
|
||||
element.classList.add(this.FILE_UNDERLINE_CLASS);
|
||||
element.style.setProperty(this.FILE_UNDERLINE_COLOR_VAR, color);
|
||||
}
|
||||
|
||||
private applyStatusDot(
|
||||
element?: HTMLElement | null,
|
||||
color?: string,
|
||||
hasStatus?: boolean,
|
||||
): void {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
const existingDot = element.querySelector(
|
||||
`.${this.STATUS_DOT_CLASS}`,
|
||||
) as HTMLElement | null;
|
||||
if (
|
||||
!settingsService.settings.fileExplorerStatusDot ||
|
||||
!hasStatus ||
|
||||
!color
|
||||
) {
|
||||
if (existingDot) {
|
||||
existingDot.remove();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const dot =
|
||||
existingDot ||
|
||||
createSpan({
|
||||
cls: this.STATUS_DOT_CLASS,
|
||||
});
|
||||
|
||||
dot.setAttribute("aria-hidden", "true");
|
||||
dot.style.backgroundColor = color;
|
||||
|
||||
if (!existingDot) {
|
||||
element.appendChild(dot);
|
||||
}
|
||||
}
|
||||
|
||||
private getNavItemElement(
|
||||
element?: HTMLElement | null,
|
||||
): HTMLElement | null {
|
||||
|
|
@ -388,8 +459,24 @@ export class FileExplorerIntegration implements IElementProcessor {
|
|||
delete element.dataset[this.FILE_NAME_COLORIZED_ATTR];
|
||||
}
|
||||
|
||||
private clearFileBlockColor(navItem: HTMLElement): void {
|
||||
private clearFileBlockColor(navItem?: HTMLElement | null): void {
|
||||
if (!navItem) {
|
||||
return;
|
||||
}
|
||||
navItem.classList.remove(this.FILE_BLOCK_CLASS);
|
||||
navItem.style.removeProperty(this.FILE_BLOCK_COLOR_VAR);
|
||||
}
|
||||
|
||||
private clearFileLeftBorder(navItem?: HTMLElement | null): void {
|
||||
if (!navItem) {
|
||||
return;
|
||||
}
|
||||
navItem.classList.remove(this.FILE_BORDER_CLASS);
|
||||
navItem.style.removeProperty(this.FILE_BORDER_COLOR_VAR);
|
||||
}
|
||||
|
||||
private clearFileNameUnderline(element: HTMLElement): void {
|
||||
element.classList.remove(this.FILE_UNDERLINE_CLASS);
|
||||
element.style.removeProperty(this.FILE_UNDERLINE_COLOR_VAR);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -31,6 +31,42 @@
|
|||
opacity var(--anim-duration-fast) ease;
|
||||
}
|
||||
|
||||
.note-status-border-left {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.note-status-border-left::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 2px;
|
||||
bottom: 2px;
|
||||
width: 3px;
|
||||
border-radius: var(--radius-s);
|
||||
background-color: var(--note-status-border-color, transparent);
|
||||
opacity: 0.35;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.note-status-underline {
|
||||
text-decoration-line: underline;
|
||||
text-decoration-thickness: 2px;
|
||||
text-decoration-color: var(--note-status-underline-color, currentColor);
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
.note-status-dot-badge {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
margin-left: var(--size-2-1);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 0 0 1px var(--background-modifier-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ export type PluginSettings = {
|
|||
showStatusIconsInExplorer: boolean;
|
||||
hideUnknownStatusInExplorer: boolean;
|
||||
fileExplorerColorFileName: boolean; // Whether to color the file explorer filename text using the current status color
|
||||
fileExplorerColorBlock: boolean; // Whether to color the entire file explorer block background with the status color
|
||||
fileExplorerColorBlock: boolean; // Whether to tint the entire explorer list item background using the status color
|
||||
fileExplorerLeftBorder: boolean; // Whether to display a colored border on the explorer item
|
||||
fileExplorerStatusDot: boolean; // Whether to append a small colored dot next to the filename
|
||||
fileExplorerUnderlineFileName: boolean; // Whether to underline the filename using the status color
|
||||
enabledTemplates: string[]; // IDs of enabled templates
|
||||
useCustomStatusesOnly: boolean; // Whether to use only custom statuses or include templates
|
||||
useMultipleStatuses: boolean; // Whether to allow multiple statuses per note
|
||||
|
|
|
|||
Loading…
Reference in a new issue