mirror of
https://github.com/devonthesofa/obsidian-note-status.git
synced 2026-07-22 12:30:24 +00:00
Merge pull request #56 from devonthesofa/feature/toolbar-button
[Feature] toolbar button
This commit is contained in:
commit
d100b5b171
10 changed files with 2054 additions and 2 deletions
|
|
@ -169,6 +169,71 @@ export const UISettings: React.FC<Props> = ({ settings, onChange }) => {
|
|||
}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<h4>Editor Toolbar Button</h4>
|
||||
|
||||
<SettingItem
|
||||
name="Show editor toolbar button"
|
||||
description="Display status button in the editor toolbar"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={settings.showEditorToolbarButton ?? true}
|
||||
onChange={handleChange("showEditorToolbarButton")}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
name="Editor toolbar button position"
|
||||
description="Choose where to position the status button in the editor toolbar"
|
||||
>
|
||||
<Select
|
||||
options={[
|
||||
{
|
||||
value: "left",
|
||||
display: "Left side of toolbar",
|
||||
},
|
||||
{
|
||||
value: "right",
|
||||
display: "Right side (after all buttons)",
|
||||
},
|
||||
{
|
||||
value: "right-before",
|
||||
display: "Right side (before action buttons)",
|
||||
},
|
||||
]}
|
||||
defaultValue={
|
||||
settings.editorToolbarButtonPosition || "right"
|
||||
}
|
||||
onChange={(value) =>
|
||||
onChange("editorToolbarButtonPosition", value)
|
||||
}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
name="Editor toolbar button display"
|
||||
description="Control which notes show the status button"
|
||||
>
|
||||
<Select
|
||||
options={[
|
||||
{
|
||||
value: "all-notes",
|
||||
display: "All open notes",
|
||||
},
|
||||
{
|
||||
value: "active-only",
|
||||
display: "Active note only",
|
||||
},
|
||||
]}
|
||||
defaultValue={
|
||||
settings.editorToolbarButtonDisplay || "all-notes"
|
||||
}
|
||||
onChange={(value) =>
|
||||
onChange("editorToolbarButtonDisplay", value)
|
||||
}
|
||||
/>
|
||||
</SettingItem>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
108
components/Toolbar/EditorToolbarButton.tsx
Normal file
108
components/Toolbar/EditorToolbarButton.tsx
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import React, { FC, memo } from "react";
|
||||
import { GroupedStatuses } from "@/types/noteStatus";
|
||||
import { StatusesInfoPopup } from "@/integrations/popups/statusesInfoPopupIntegration";
|
||||
|
||||
interface EditorToolbarButtonProps {
|
||||
statuses: GroupedStatuses;
|
||||
onClick: () => void;
|
||||
unknownStatusConfig: {
|
||||
icon: string;
|
||||
color: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const EditorToolbarButton: FC<EditorToolbarButtonProps> = memo(
|
||||
({ statuses, onClick, unknownStatusConfig }) => {
|
||||
const statusEntries = Object.entries(statuses);
|
||||
const allStatuses = statusEntries.flatMap(
|
||||
([_, statusList]) => statusList,
|
||||
);
|
||||
const totalStatuses = allStatuses.length;
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
StatusesInfoPopup.open(statuses);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
StatusesInfoPopup.close();
|
||||
};
|
||||
|
||||
const getPrimaryStatus = () => allStatuses[0];
|
||||
|
||||
// No status state
|
||||
if (totalStatuses === 0) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="clickable-icon"
|
||||
onClick={onClick}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
aria-label="Add status to note"
|
||||
>
|
||||
<span
|
||||
className="editor-toolbar-button__icon"
|
||||
style={{ color: unknownStatusConfig.color }}
|
||||
>
|
||||
{unknownStatusConfig.icon}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
const primaryStatus = getPrimaryStatus();
|
||||
|
||||
// Single status
|
||||
if (totalStatuses === 1) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="clickable-icon"
|
||||
onClick={onClick}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
aria-label={`Current status: ${primaryStatus.name}. Click to change.`}
|
||||
>
|
||||
<span
|
||||
className="editor-toolbar-button__icon editor-toolbar-button__icon--has-status"
|
||||
style={{
|
||||
color:
|
||||
primaryStatus.color ||
|
||||
"var(--interactive-accent)",
|
||||
}}
|
||||
>
|
||||
{primaryStatus.icon || "📝"}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
// Multiple statuses - show primary + counter
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="clickable-icon"
|
||||
onClick={onClick}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
aria-label={`${totalStatuses} statuses assigned. Click to change.`}
|
||||
>
|
||||
<div className="editor-toolbar-button__icon-container">
|
||||
<span
|
||||
className="editor-toolbar-button__icon editor-toolbar-button__icon--has-status"
|
||||
style={{
|
||||
color:
|
||||
primaryStatus.color ||
|
||||
"var(--interactive-accent)",
|
||||
}}
|
||||
>
|
||||
{primaryStatus.icon || "📝"}
|
||||
</span>
|
||||
<span className="editor-toolbar-button__counter">
|
||||
{totalStatuses}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
@ -103,7 +103,7 @@ export const StatusDisplay: FC<StatusDisplayProps> = memo(
|
|||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
<ObsidianIcon name="thrash" size={12} />
|
||||
<ObsidianIcon name="trash" size={12} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -33,4 +33,8 @@ export const DEFAULT_PLUGIN_SETTINGS: PluginSettings = {
|
|||
statusBarShowNoStatusIcon: false,
|
||||
statusBarShowNoStatusText: true,
|
||||
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
|
||||
editorToolbarButtonPosition: "right", // Default position on the right
|
||||
editorToolbarButtonDisplay: "all-notes", // Default to show button in all notes
|
||||
};
|
||||
|
|
|
|||
386
integrations/toolbar/editorToolbarIntegration.tsx
Normal file
386
integrations/toolbar/editorToolbarIntegration.tsx
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
import { createRoot, Root } from "react-dom/client";
|
||||
import eventBus from "core/eventBus";
|
||||
import { MarkdownView, Plugin, WorkspaceLeaf } from "obsidian";
|
||||
import settingsService from "@/core/settingsService";
|
||||
import { EditorToolbarButton } from "@/components/Toolbar/EditorToolbarButton";
|
||||
import { NoteStatusService } from "@/core/noteStatusService";
|
||||
|
||||
interface LeafButton {
|
||||
leaf: WorkspaceLeaf;
|
||||
root: Root;
|
||||
buttonElement: HTMLElement;
|
||||
noteStatusService: NoteStatusService;
|
||||
}
|
||||
|
||||
export class EditorToolbarIntegration {
|
||||
private static instance: EditorToolbarIntegration | null = null;
|
||||
private plugin: Plugin;
|
||||
private leafButtons: Map<WorkspaceLeaf, LeafButton> = new Map();
|
||||
private currentActiveLeaf: WorkspaceLeaf | null = null;
|
||||
private readonly BUTTON_CLASS = "note-status-editor-toolbar-badge";
|
||||
|
||||
constructor(plugin: Plugin) {
|
||||
if (EditorToolbarIntegration.instance) {
|
||||
throw new Error("The editor toolbar instance is already created");
|
||||
}
|
||||
this.plugin = plugin;
|
||||
EditorToolbarIntegration.instance = this;
|
||||
}
|
||||
|
||||
async integrate() {
|
||||
// Initialize the current active leaf
|
||||
const activeLeaf = this.plugin.app.workspace.activeLeaf;
|
||||
if (activeLeaf && this.isValidMarkdownLeaf(activeLeaf)) {
|
||||
this.currentActiveLeaf = activeLeaf;
|
||||
}
|
||||
|
||||
// Initialize buttons based on display mode
|
||||
this.initializeButtons();
|
||||
|
||||
// Listen for new leaves being created
|
||||
this.plugin.registerEvent(
|
||||
this.plugin.app.workspace.on("layout-change", () => {
|
||||
this.handleLayoutChange();
|
||||
}),
|
||||
);
|
||||
|
||||
eventBus.subscribe(
|
||||
"active-file-change",
|
||||
({ leaf }) => {
|
||||
this.currentActiveLeaf =
|
||||
leaf && this.isValidMarkdownLeaf(leaf) ? leaf : null;
|
||||
this.handleActiveLeafChange();
|
||||
},
|
||||
"editorToolbarIntegrationSubscription1",
|
||||
);
|
||||
|
||||
eventBus.subscribe(
|
||||
"plugin-settings-changed",
|
||||
({ key }) => {
|
||||
if (key === "enabledTemplates" || key === "templates") {
|
||||
this.refreshAllButtons();
|
||||
}
|
||||
if (key === "useMultipleStatuses") {
|
||||
this.refreshAllButtons();
|
||||
}
|
||||
if (key === "tagPrefix") {
|
||||
this.refreshAllButtons();
|
||||
}
|
||||
if (key === "useCustomStatusesOnly") {
|
||||
this.refreshAllButtons();
|
||||
}
|
||||
if (key === "customStatuses") {
|
||||
this.refreshAllButtons();
|
||||
}
|
||||
if (
|
||||
key === "unknownStatusIcon" ||
|
||||
key === "unknownStatusColor"
|
||||
) {
|
||||
this.renderAllButtons();
|
||||
}
|
||||
if (key === "showEditorToolbarButton") {
|
||||
this.handleShowHideButtons();
|
||||
}
|
||||
if (key === "editorToolbarButtonPosition") {
|
||||
this.recreateAllButtons();
|
||||
}
|
||||
if (key === "editorToolbarButtonDisplay") {
|
||||
this.handleDisplayModeChange();
|
||||
}
|
||||
},
|
||||
"editorToolbarIntegrationSubscription2",
|
||||
);
|
||||
|
||||
eventBus.subscribe(
|
||||
"frontmatter-manually-changed",
|
||||
({ file }) => {
|
||||
// Find the button for the specific file and refresh only that one
|
||||
for (const [leaf, leafButton] of this.leafButtons.entries()) {
|
||||
const markdownView = leaf.view as MarkdownView;
|
||||
if (markdownView.file === file) {
|
||||
leafButton.noteStatusService = new NoteStatusService(
|
||||
file,
|
||||
);
|
||||
leafButton.noteStatusService.populateStatuses();
|
||||
this.renderButtonForLeaf(leafButton);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"editorToolbarIntegrationSubscription3",
|
||||
);
|
||||
}
|
||||
|
||||
private initializeButtons() {
|
||||
const targetLeaves = this.getTargetLeaves();
|
||||
for (const leaf of targetLeaves) {
|
||||
this.createButtonForLeaf(leaf);
|
||||
}
|
||||
}
|
||||
|
||||
private handleActiveLeafChange() {
|
||||
this.syncButtons();
|
||||
}
|
||||
|
||||
private handleDisplayModeChange() {
|
||||
this.syncButtons();
|
||||
}
|
||||
|
||||
private syncButtons() {
|
||||
const targetLeaves = new Set(this.getTargetLeaves());
|
||||
|
||||
// Remove buttons that shouldn't exist
|
||||
for (const leaf of this.leafButtons.keys()) {
|
||||
if (!targetLeaves.has(leaf)) {
|
||||
this.removeButtonForLeaf(leaf);
|
||||
}
|
||||
}
|
||||
|
||||
// Add buttons that should exist but don't
|
||||
for (const leaf of targetLeaves) {
|
||||
if (!this.leafButtons.has(leaf)) {
|
||||
this.createButtonForLeaf(leaf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private handleLayoutChange() {
|
||||
this.syncButtons();
|
||||
}
|
||||
|
||||
private createButtonForLeaf(leaf: WorkspaceLeaf) {
|
||||
if (!this.isValidMarkdownLeaf(leaf)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove existing button if it exists
|
||||
if (this.leafButtons.has(leaf)) {
|
||||
this.removeButtonForLeaf(leaf);
|
||||
}
|
||||
|
||||
// Check if toolbar button should be shown
|
||||
if (!settingsService.settings.showEditorToolbarButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
const markdownView = leaf.view as MarkdownView;
|
||||
if (!markdownView.file) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create note status service for this leaf
|
||||
const noteStatusService = new NoteStatusService(markdownView.file);
|
||||
noteStatusService.populateStatuses();
|
||||
|
||||
// Create button element
|
||||
const buttonElement = this.createButtonElement(leaf);
|
||||
if (!buttonElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create React root
|
||||
const root = createRoot(buttonElement);
|
||||
|
||||
// Store the button info
|
||||
const leafButton: LeafButton = {
|
||||
leaf,
|
||||
root,
|
||||
buttonElement,
|
||||
noteStatusService,
|
||||
};
|
||||
|
||||
this.leafButtons.set(leaf, leafButton);
|
||||
|
||||
// Render the button
|
||||
this.renderButtonForLeaf(leafButton);
|
||||
}
|
||||
|
||||
private isValidMarkdownLeaf(leaf: WorkspaceLeaf | null): boolean {
|
||||
return leaf !== null && leaf.view.getViewType() === "markdown";
|
||||
}
|
||||
|
||||
private shouldHaveButton(leaf: WorkspaceLeaf): boolean {
|
||||
if (
|
||||
!settingsService.settings.showEditorToolbarButton ||
|
||||
!this.isValidMarkdownLeaf(leaf)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
settingsService.settings.editorToolbarButtonDisplay ===
|
||||
"all-notes" || leaf === this.currentActiveLeaf
|
||||
);
|
||||
}
|
||||
|
||||
private getTargetLeaves(): WorkspaceLeaf[] {
|
||||
const leaves: WorkspaceLeaf[] = [];
|
||||
|
||||
if (
|
||||
settingsService.settings.editorToolbarButtonDisplay ===
|
||||
"active-only"
|
||||
) {
|
||||
if (
|
||||
this.currentActiveLeaf &&
|
||||
this.isValidMarkdownLeaf(this.currentActiveLeaf)
|
||||
) {
|
||||
leaves.push(this.currentActiveLeaf);
|
||||
}
|
||||
} else {
|
||||
this.plugin.app.workspace.iterateAllLeaves((leaf) => {
|
||||
if (this.isValidMarkdownLeaf(leaf)) {
|
||||
leaves.push(leaf);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return leaves;
|
||||
}
|
||||
|
||||
private createButtonElement(leaf: WorkspaceLeaf): HTMLElement | null {
|
||||
const markdownView = leaf.view as MarkdownView;
|
||||
const position = settingsService.settings.editorToolbarButtonPosition;
|
||||
|
||||
// Find the appropriate container based on position
|
||||
let targetContainer: Element | null = null;
|
||||
|
||||
if (position === "left") {
|
||||
// For left position, use the nav buttons area or title container
|
||||
targetContainer =
|
||||
markdownView.containerEl.querySelector(
|
||||
".view-header-nav-buttons",
|
||||
) ||
|
||||
markdownView.containerEl.querySelector(
|
||||
".view-header-title-container",
|
||||
) ||
|
||||
markdownView.containerEl.querySelector(".view-header-left");
|
||||
} else {
|
||||
// For right positions, use the view-actions container
|
||||
targetContainer =
|
||||
markdownView.containerEl.querySelector(".view-actions");
|
||||
}
|
||||
|
||||
if (!targetContainer) {
|
||||
console.warn(
|
||||
"Could not find target container for editor toolbar button",
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const buttonElement = document.createElement("div");
|
||||
buttonElement.className = this.BUTTON_CLASS;
|
||||
|
||||
// Insert button based on position setting
|
||||
if (position === "left") {
|
||||
// For left, insert after existing nav buttons
|
||||
targetContainer.appendChild(buttonElement);
|
||||
} else if (position === "right-before") {
|
||||
// For right-before, insert at the beginning of actions
|
||||
targetContainer.insertBefore(
|
||||
buttonElement,
|
||||
targetContainer.firstChild,
|
||||
);
|
||||
} else {
|
||||
// For right, insert at the end of actions
|
||||
targetContainer.appendChild(buttonElement);
|
||||
}
|
||||
|
||||
return buttonElement;
|
||||
}
|
||||
|
||||
private removeButtonForLeaf(leaf: WorkspaceLeaf): void {
|
||||
const leafButton = this.leafButtons.get(leaf);
|
||||
if (leafButton) {
|
||||
leafButton.root.unmount();
|
||||
leafButton.buttonElement.remove();
|
||||
this.leafButtons.delete(leaf);
|
||||
}
|
||||
}
|
||||
|
||||
private renderButtonForLeaf(leafButton: LeafButton): void {
|
||||
leafButton.root.render(
|
||||
<EditorToolbarButton
|
||||
statuses={leafButton.noteStatusService?.statuses || {}}
|
||||
onClick={() =>
|
||||
this.openStatusModal(leafButton.noteStatusService)
|
||||
}
|
||||
unknownStatusConfig={this.getUnknownStatusConfig()}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
private refreshAllButtons(): void {
|
||||
for (const [leaf, leafButton] of this.leafButtons.entries()) {
|
||||
const markdownView = leaf.view as MarkdownView;
|
||||
if (markdownView.file) {
|
||||
leafButton.noteStatusService = new NoteStatusService(
|
||||
markdownView.file,
|
||||
);
|
||||
leafButton.noteStatusService.populateStatuses();
|
||||
this.renderButtonForLeaf(leafButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private renderAllButtons(): void {
|
||||
for (const leafButton of this.leafButtons.values()) {
|
||||
this.renderButtonForLeaf(leafButton);
|
||||
}
|
||||
}
|
||||
|
||||
private handleShowHideButtons(): void {
|
||||
this.syncButtons();
|
||||
}
|
||||
|
||||
private recreateAllButtons(): void {
|
||||
// Remove all existing buttons first
|
||||
for (const leaf of this.leafButtons.keys()) {
|
||||
this.removeButtonForLeaf(leaf);
|
||||
}
|
||||
this.syncButtons();
|
||||
}
|
||||
|
||||
private openStatusModal(noteStatusService: NoteStatusService) {
|
||||
if (!noteStatusService) {
|
||||
throw new Error(
|
||||
"open status modal failed because there is no noteStatusService available",
|
||||
);
|
||||
}
|
||||
eventBus.publish("triggered-open-modal", {
|
||||
statusService: noteStatusService,
|
||||
});
|
||||
}
|
||||
|
||||
private getUnknownStatusConfig() {
|
||||
const settings = settingsService.settings;
|
||||
return {
|
||||
icon: settings.unknownStatusIcon || "❓",
|
||||
color: settings.unknownStatusColor || "#8b949e",
|
||||
};
|
||||
}
|
||||
|
||||
destroy() {
|
||||
eventBus.unsubscribe(
|
||||
"active-file-change",
|
||||
"editorToolbarIntegrationSubscription1",
|
||||
);
|
||||
eventBus.unsubscribe(
|
||||
"plugin-settings-changed",
|
||||
"editorToolbarIntegrationSubscription2",
|
||||
);
|
||||
eventBus.unsubscribe(
|
||||
"frontmatter-manually-changed",
|
||||
"editorToolbarIntegrationSubscription3",
|
||||
);
|
||||
|
||||
// Remove all buttons
|
||||
for (const leaf of this.leafButtons.keys()) {
|
||||
this.removeButtonForLeaf(leaf);
|
||||
}
|
||||
|
||||
this.leafButtons.clear();
|
||||
EditorToolbarIntegration.instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
export default EditorToolbarIntegration;
|
||||
9
main.tsx
9
main.tsx
|
|
@ -8,6 +8,7 @@ import { StatusModalIntegration } from "./integrations/modals/statusModalIntegra
|
|||
import ContextMenuIntegration from "./integrations/context-menu/contextMenuIntegration";
|
||||
import { FileExplorerIntegration } from "./integrations/file-explorer/file-explorer-integration";
|
||||
import { CommandsIntegration } from "./integrations/commands/commandsIntegration";
|
||||
import EditorToolbarIntegration from "./integrations/toolbar/editorToolbarIntegration";
|
||||
import {
|
||||
GroupedStatusView,
|
||||
VIEW_TYPE_EXAMPLE,
|
||||
|
|
@ -23,6 +24,7 @@ export default class NoteStatusPlugin extends Plugin {
|
|||
private contextMenuIntegration: ContextMenuIntegration;
|
||||
private fileExplorerIntegration: FileExplorerIntegration;
|
||||
private commandsIntegration: CommandsIntegration;
|
||||
private editorToolbarIntegration: EditorToolbarIntegration;
|
||||
|
||||
async onload() {
|
||||
BaseNoteStatusService.initialize(this.app);
|
||||
|
|
@ -34,6 +36,7 @@ export default class NoteStatusPlugin extends Plugin {
|
|||
this.loadStatusBar(),
|
||||
this.loadFileExplorer(),
|
||||
this.loadCommands(),
|
||||
this.loadEditorToolbar(),
|
||||
this.loadEventBus(),
|
||||
]);
|
||||
|
||||
|
|
@ -62,6 +65,7 @@ export default class NoteStatusPlugin extends Plugin {
|
|||
this.contextMenuIntegration?.destroy();
|
||||
this.fileExplorerIntegration?.destroy();
|
||||
this.commandsIntegration?.destroy();
|
||||
this.editorToolbarIntegration?.destroy();
|
||||
this.pluginSettingsIntegration?.destroy();
|
||||
|
||||
// Clean up event subscriptions
|
||||
|
|
@ -188,4 +192,9 @@ export default class NoteStatusPlugin extends Plugin {
|
|||
this.commandsIntegration = new CommandsIntegration(this);
|
||||
await this.commandsIntegration.integrate();
|
||||
}
|
||||
|
||||
private async loadEditorToolbar() {
|
||||
this.editorToolbarIntegration = new EditorToolbarIntegration(this);
|
||||
await this.editorToolbarIntegration.integrate();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1420
styles.css
1420
styles.css
File diff suppressed because one or more lines are too long
57
styles/components/toolbar-button.css
Normal file
57
styles/components/toolbar-button.css
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* Editor Toolbar Button - Using Obsidian's native clickable-icon styling */
|
||||
|
||||
/* Container styling for proper integration */
|
||||
.note-status-editor-toolbar-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin: 0 var(--size-2-1);
|
||||
}
|
||||
|
||||
/* Hidden state */
|
||||
.note-status-editor-toolbar-badge--hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* BEM-based styles for toolbar button components */
|
||||
|
||||
/* Status icon styling */
|
||||
.editor-toolbar-button__icon {
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* Icon with status color */
|
||||
.editor-toolbar-button__icon--has-status {
|
||||
color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
/* Multiple statuses container */
|
||||
.editor-toolbar-button__icon-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Status counter badge */
|
||||
.editor-toolbar-button__counter {
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -6px;
|
||||
min-width: 12px;
|
||||
height: 12px;
|
||||
padding: 0 2px;
|
||||
background: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
font-size: 8px;
|
||||
font-weight: var(--font-semibold);
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
border: 1px solid var(--background-primary);
|
||||
}
|
||||
|
|
@ -16,3 +16,4 @@
|
|||
@import "components/collapsible-counter.css";
|
||||
@import "components/status-display.css";
|
||||
@import "components/obsidian-icon.css";
|
||||
@import "components/toolbar-button.css";
|
||||
|
|
|
|||
|
|
@ -33,5 +33,9 @@ export type PluginSettings = {
|
|||
statusBarShowNoStatusIcon: boolean; // Whether to show icon in status bar for no status
|
||||
statusBarShowNoStatusText: boolean; // Whether to show text in status bar for no status
|
||||
vaultSizeLimit: number; // Disable dashboard and grouped view for vaults with more notes than this limit
|
||||
// Editor toolbar button settings
|
||||
showEditorToolbarButton: boolean; // Whether to show the toolbar button
|
||||
editorToolbarButtonPosition: "left" | "right" | "right-before"; // Position of the toolbar button
|
||||
editorToolbarButtonDisplay: "all-notes" | "active-only"; // Whether to show button in all notes or only active one
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue