mirror of
https://github.com/devonthesofa/obsidian-note-status.git
synced 2026-07-22 12:30:24 +00:00
Merge pull request #42 from devonthesofa/chore/readme-wiki-v2
chore: improve README and Wiki integration, UI fixes and cleanup
This commit is contained in:
commit
1cf39cb2a1
23 changed files with 305 additions and 410 deletions
47
.gitignore
vendored
47
.gitignore
vendored
|
|
@ -1,23 +1,24 @@
|
|||
# vscode
|
||||
.vscode
|
||||
|
||||
# Intellij
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
|
||||
# Don't include the compiled main.js file in the repo.
|
||||
# They should be uploaded to GitHub releases instead.
|
||||
main.js
|
||||
|
||||
# Exclude sourcemaps
|
||||
*.map
|
||||
|
||||
# obsidian
|
||||
data.json
|
||||
|
||||
# Exclude macOS Finder (System Explorer) View States
|
||||
.DS_Store
|
||||
styles.css
|
||||
# vscode
|
||||
.vscode
|
||||
|
||||
# Intellij
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
|
||||
# Don't include the compiled main.js file in the repo.
|
||||
# They should be uploaded to GitHub releases instead.
|
||||
main.js
|
||||
|
||||
# Exclude sourcemaps
|
||||
*.map
|
||||
|
||||
# obsidian
|
||||
data.json
|
||||
|
||||
# Exclude macOS Finder (System Explorer) View States
|
||||
.DS_Store
|
||||
styles.css
|
||||
.obsidian
|
||||
|
|
|
|||
1
.obsidian/app.json
vendored
1
.obsidian/app.json
vendored
|
|
@ -1 +0,0 @@
|
|||
{}
|
||||
1
.obsidian/appearance.json
vendored
1
.obsidian/appearance.json
vendored
|
|
@ -1 +0,0 @@
|
|||
{}
|
||||
31
.obsidian/core-plugins.json
vendored
31
.obsidian/core-plugins.json
vendored
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"file-explorer": true,
|
||||
"global-search": true,
|
||||
"switcher": true,
|
||||
"graph": true,
|
||||
"backlink": true,
|
||||
"canvas": true,
|
||||
"outgoing-link": true,
|
||||
"tag-pane": true,
|
||||
"properties": false,
|
||||
"page-preview": true,
|
||||
"daily-notes": true,
|
||||
"templates": true,
|
||||
"note-composer": true,
|
||||
"command-palette": true,
|
||||
"slash-command": false,
|
||||
"editor-status": true,
|
||||
"bookmarks": true,
|
||||
"markdown-importer": false,
|
||||
"zk-prefixer": false,
|
||||
"random-note": false,
|
||||
"outline": true,
|
||||
"word-count": true,
|
||||
"slides": false,
|
||||
"audio-recorder": false,
|
||||
"workspaces": false,
|
||||
"file-recovery": true,
|
||||
"publish": false,
|
||||
"sync": true,
|
||||
"webviewer": false
|
||||
}
|
||||
191
.obsidian/workspace.json
vendored
191
.obsidian/workspace.json
vendored
|
|
@ -1,191 +0,0 @@
|
|||
{
|
||||
"main": {
|
||||
"id": "886965717aacb6d0",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "9481425cee5d18ea",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "1eb2e9c2c530a169",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "README.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "README"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "87a5f93795884bb0",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "empty",
|
||||
"state": {},
|
||||
"icon": "lucide-file",
|
||||
"title": "New tab"
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentTab": 1
|
||||
}
|
||||
],
|
||||
"direction": "vertical"
|
||||
},
|
||||
"left": {
|
||||
"id": "580f4711e49ff790",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "2b68b0e26714f9db",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "9a2de93776a5f52a",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "file-explorer",
|
||||
"state": {
|
||||
"sortOrder": "alphabetical",
|
||||
"autoReveal": true
|
||||
},
|
||||
"icon": "lucide-folder-closed",
|
||||
"title": "Files"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "c1f9ccb674013288",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "search",
|
||||
"state": {
|
||||
"query": "",
|
||||
"matchingCase": false,
|
||||
"explainSearch": false,
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical"
|
||||
},
|
||||
"icon": "lucide-search",
|
||||
"title": "Search"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "1d6b9ea734b0a656",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "bookmarks",
|
||||
"state": {},
|
||||
"icon": "lucide-bookmark",
|
||||
"title": "Bookmarks"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "horizontal",
|
||||
"width": 300
|
||||
},
|
||||
"right": {
|
||||
"id": "267e362ff570d883",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "beba4aa22886cb5b",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "1f3a1273479a0100",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "backlink",
|
||||
"state": {
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical",
|
||||
"showSearch": false,
|
||||
"searchQuery": "",
|
||||
"backlinkCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
},
|
||||
"icon": "links-coming-in",
|
||||
"title": "Backlinks"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "a50a231b68e4c2c8",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "outgoing-link",
|
||||
"state": {
|
||||
"linksCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
},
|
||||
"icon": "links-going-out",
|
||||
"title": "Outgoing links"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "760ee1f1f13bf340",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "tag",
|
||||
"state": {
|
||||
"sortOrder": "frequency",
|
||||
"useHierarchy": true,
|
||||
"showSearch": false,
|
||||
"searchQuery": ""
|
||||
},
|
||||
"icon": "lucide-tags",
|
||||
"title": "Tags"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "e8291e1c7436943b",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "outline",
|
||||
"state": {
|
||||
"followCursor": false,
|
||||
"showSearch": false,
|
||||
"searchQuery": ""
|
||||
},
|
||||
"icon": "lucide-list",
|
||||
"title": "Outline"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "horizontal",
|
||||
"width": 300
|
||||
},
|
||||
"left-ribbon": {
|
||||
"hiddenItems": {
|
||||
"switcher:Open quick switcher": false,
|
||||
"graph:Open graph view": false,
|
||||
"canvas:Create new canvas": false,
|
||||
"daily-notes:Open today's daily note": false,
|
||||
"templates:Insert template": false,
|
||||
"command-palette:Open command palette": false
|
||||
}
|
||||
},
|
||||
"active": "87a5f93795884bb0",
|
||||
"lastOpenFiles": [
|
||||
"README.md",
|
||||
"wiki/User Manual.md",
|
||||
"wiki/Quick Start Guide.md",
|
||||
"wiki/Performance Tuning.md",
|
||||
"wiki/Home Page.md",
|
||||
"wiki/Frontmatter Format.md",
|
||||
"wiki/Development Setup.md",
|
||||
"wiki/Configuration Guide.md",
|
||||
"wiki/Architecture Overview.md",
|
||||
"wiki"
|
||||
]
|
||||
}
|
||||
10
README.md
10
README.md
|
|
@ -8,13 +8,13 @@ Track the status of your notes with a powerful, customizable status management s
|
|||
|
||||
- **📋 Status Assignment**: Mark notes with workflow statuses
|
||||
- **🎯 Multi-Status Support**: Assign multiple statuses per note
|
||||
- **📁 File Explorer Icons**: Visual indicators in the file tree
|
||||
- **🧭 Status Bar Integration**: View current status at a glance
|
||||
- **📁 File Explorer Icons**: Visual indicators in the file tree with configurable positioning
|
||||
- **🧭 Status Bar Integration**: View current status at a glance with custom unknown status icons
|
||||
- **⬇️ Toolbar Dropdown**: Change statuses quickly from the editor
|
||||
- **📊 Status Pane**: Dedicated view organizing notes by status
|
||||
- **📊 Status Pane**: Dedicated view organizing notes by status with command palette access
|
||||
- **⚡ Batch Operations**: Update multiple files simultaneously
|
||||
- **🎨 Custom Statuses**: Define your own statuses
|
||||
- **🧩 Templates Library**: Use built-in templates
|
||||
- **🎨 Custom Statuses**: Define and reorder your own statuses with arrow controls
|
||||
- **🧩 Template-Based Filtering**: Scope statuses by note templates for better organization
|
||||
- **🔧 Full Customization**: Control how and where statuses appear
|
||||
- **🚀 Performance**: Optimized for large vaults (40k+ notes tested)
|
||||

|
||||
|
|
|
|||
|
|
@ -47,7 +47,10 @@ export const StatusGroup = ({
|
|||
|
||||
return (
|
||||
<div className="grouped-status-group">
|
||||
<div className="grouped-status-group-header" onClick={handleToggle}>
|
||||
<div
|
||||
className="grouped-status-group__header"
|
||||
onClick={handleToggle}
|
||||
>
|
||||
<div className="grouped-status-group__status">
|
||||
<StatusDisplay
|
||||
status={
|
||||
|
|
@ -61,7 +64,7 @@ export const StatusGroup = ({
|
|||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="grouped-status-group-info">
|
||||
<div className="grouped-status-group__info">
|
||||
<CollapsibleCounter
|
||||
count={files.length}
|
||||
isCollapsed={!isExpanded}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import React from "react";
|
||||
import { PluginSettings } from "@/types/pluginSettings";
|
||||
import { SettingItem } from "./SettingItem";
|
||||
|
||||
export type StatusGroupProps = {
|
||||
statuses: PluginSettings["customStatuses"];
|
||||
|
|
@ -18,28 +17,52 @@ export const StatusGroup: React.FC<StatusGroupProps> = ({
|
|||
onToggle,
|
||||
}) => (
|
||||
<div className="status-group">
|
||||
<div className="status-group-header">
|
||||
<div className="status-group-title">{title}</div>
|
||||
<div className="status-group__header">
|
||||
<div className="status-group__title">{title}</div>
|
||||
{description && (
|
||||
<div className="status-group-description">{description}</div>
|
||||
<div className="status-group__description">{description}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="status-group-items">
|
||||
{statuses.map((status) => (
|
||||
<SettingItem
|
||||
key={`${status.templateId || "custom"}:${status.name}`}
|
||||
name={`${status.icon} ${status.name}`}
|
||||
description={status.description || ""}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={currentQuickCommands.includes(status.name)}
|
||||
onChange={(e) =>
|
||||
onToggle(status.name, e.target.checked)
|
||||
}
|
||||
/>
|
||||
</SettingItem>
|
||||
))}
|
||||
<div className="status-group__items">
|
||||
{statuses.map((status) => {
|
||||
const scopedStatusName = status.templateId
|
||||
? `${status.templateId}:${status.name}`
|
||||
: status.name;
|
||||
|
||||
const isSelected =
|
||||
currentQuickCommands.includes(scopedStatusName);
|
||||
|
||||
return (
|
||||
<label
|
||||
key={`${status.templateId || "custom"}:${status.name}`}
|
||||
className={`status-selector ${isSelected ? "status-selector--selected" : ""}`}
|
||||
>
|
||||
<div className="status-selector__content">
|
||||
<div className="status-selector__status">
|
||||
<span className="status-selector__icon">
|
||||
{status.icon}
|
||||
</span>
|
||||
<span className="status-selector__name">
|
||||
{status.name}
|
||||
</span>
|
||||
</div>
|
||||
{status.description && (
|
||||
<div className="status-selector__description">
|
||||
{status.description}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="status-selector__checkbox"
|
||||
checked={isSelected}
|
||||
onChange={(e) =>
|
||||
onToggle(scopedStatusName, e.target.checked)
|
||||
}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { PluginSettings } from "@/types/pluginSettings";
|
||||
import React from "react";
|
||||
import { Input } from "../atoms/Input";
|
||||
import { Select } from "../atoms/Select";
|
||||
import { SettingItem } from "./SettingItem";
|
||||
|
||||
|
|
@ -15,18 +16,6 @@ export const UISettings: React.FC<Props> = ({ settings, onChange }) => {
|
|||
onChange(key, e.target.checked);
|
||||
};
|
||||
|
||||
const handleInputChange =
|
||||
(key: keyof PluginSettings) =>
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
onChange(key, e.target.value);
|
||||
};
|
||||
|
||||
const handleTextInputChange =
|
||||
(key: keyof PluginSettings) =>
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
onChange(key, e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="ui-settings">
|
||||
<h3>User interface</h3>
|
||||
|
|
@ -92,28 +81,18 @@ export const UISettings: React.FC<Props> = ({ settings, onChange }) => {
|
|||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
name="Exclude unassigned notes from status pane"
|
||||
description="Excludes unassigned notes from status pane for better performance. Recommended for large vaults."
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={settings.excludeUnknownStatus || false}
|
||||
onChange={handleChange("excludeUnknownStatus")}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<h4>Unknown Status Customization</h4>
|
||||
|
||||
<SettingItem
|
||||
name="Unknown status icon"
|
||||
description="Icon displayed for files with unknown status"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value={settings.unknownStatusIcon || "❓"}
|
||||
onChange={handleInputChange("unknownStatusIcon")}
|
||||
style={{ width: "60px", textAlign: "center" }}
|
||||
<Input
|
||||
variant="text"
|
||||
value={settings.unknownStatusIcon}
|
||||
onChange={(value) => onChange("unknownStatusIcon", value)}
|
||||
placeholder="❓"
|
||||
style={{ maxWidth: "150px" }}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
|
|
@ -121,11 +100,11 @@ export const UISettings: React.FC<Props> = ({ settings, onChange }) => {
|
|||
name="Unknown status color"
|
||||
description="Hex color for unknown status (e.g., #8b949e)"
|
||||
>
|
||||
<input
|
||||
type="color"
|
||||
<Input
|
||||
variant="color"
|
||||
value={settings.unknownStatusColor || "#8b949e"}
|
||||
onChange={handleInputChange("unknownStatusColor")}
|
||||
style={{ width: "50px", height: "30px" }}
|
||||
onChange={(value) => onChange("unknownStatusColor", value)}
|
||||
placeholder="No status"
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
|
|
@ -133,11 +112,13 @@ export const UISettings: React.FC<Props> = ({ settings, onChange }) => {
|
|||
name="Status bar 'no status' text"
|
||||
description="Text displayed in status bar when there is no status"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
<Input
|
||||
variant="text"
|
||||
value={settings.statusBarNoStatusText}
|
||||
onChange={handleTextInputChange("statusBarNoStatusText")}
|
||||
style={{ width: "150px" }}
|
||||
onChange={(value) =>
|
||||
onChange("statusBarNoStatusText", value)
|
||||
}
|
||||
style={{ maxWidth: "150px" }}
|
||||
placeholder="No status"
|
||||
/>
|
||||
</SettingItem>
|
||||
|
|
|
|||
|
|
@ -29,16 +29,16 @@ export const StatusFileInfoPopup: React.FC<Props> = ({ statuses }) => {
|
|||
<div className="status-popup-content">
|
||||
{statusEntries.map(([groupName, statusList]) => (
|
||||
<div key={groupName} className="status-group">
|
||||
<div className="status-group-header">
|
||||
<span className="status-group-name">
|
||||
<div className="status-group__header">
|
||||
<span className="status-group__name">
|
||||
{groupName.toLowerCase()}
|
||||
</span>
|
||||
<span className="status-group-count">
|
||||
<span className="status-group__count">
|
||||
{statusList.length}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="status-group-items">
|
||||
<div className="status-group__items">
|
||||
{statusList.map((status, index) => (
|
||||
<div
|
||||
key={`${groupName}-${index}`}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ export const DEFAULT_PLUGIN_SETTINGS: PluginSettings = {
|
|||
useMultipleStatuses: true,
|
||||
tagPrefix: "obsidian-note-status",
|
||||
strictStatuses: false, // Default to show all statuses from frontmatter
|
||||
excludeUnknownStatus: true, // Default to exclude unknown status files for better performance
|
||||
quickStatusCommands: ["active", "completed"], // Add default quick commands
|
||||
// Unknown status customization
|
||||
unknownStatusIcon: "❓",
|
||||
|
|
|
|||
|
|
@ -282,13 +282,24 @@ export class CommandsService {
|
|||
settingsService.settings.quickStatusCommands || [];
|
||||
const allStatuses = BaseNoteStatusService.getAllAvailableStatuses();
|
||||
|
||||
quickCommands.forEach((statusName) => {
|
||||
const status = allStatuses.find((s) => s.name === statusName);
|
||||
quickCommands.forEach((statusIdentifier) => {
|
||||
const parsedStatus =
|
||||
BaseNoteStatusService.parseStatusIdentifier(statusIdentifier);
|
||||
const status = allStatuses.find(
|
||||
(s) =>
|
||||
s.name === parsedStatus.name &&
|
||||
(s.templateId || null) ===
|
||||
(parsedStatus.templateId || null),
|
||||
);
|
||||
if (!status) return;
|
||||
|
||||
const displayName = parsedStatus.templateId
|
||||
? `${parsedStatus.name} (${parsedStatus.templateId})`
|
||||
: parsedStatus.name;
|
||||
|
||||
this.plugin.addCommand({
|
||||
id: `set-status-${statusName}`,
|
||||
name: `Set status to ${statusName}`,
|
||||
id: `set-status-${statusIdentifier.replace(":", "-")}`,
|
||||
name: `Set status to ${displayName}`,
|
||||
checkCallback: (checking: boolean) => {
|
||||
const file = this.app.workspace.getActiveFile();
|
||||
if (!file) return false;
|
||||
|
|
@ -314,13 +325,15 @@ export class CommandsService {
|
|||
[scopedIdentifier],
|
||||
)
|
||||
.then(() => {
|
||||
new Notice(`Status set to ${statusName}`);
|
||||
new Notice(`Status set to ${displayName}`);
|
||||
});
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
this.registeredCommands.add(`set-status-${statusName}`);
|
||||
this.registeredCommands.add(
|
||||
`set-status-${statusIdentifier.replace(":", "-")}`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -333,27 +346,18 @@ export class CommandsService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Remove all quick status commands
|
||||
* Remove all registered commands
|
||||
*/
|
||||
private removeQuickStatusCommands(): void {
|
||||
const allStatuses = BaseNoteStatusService.getAllAvailableStatuses();
|
||||
|
||||
//TODO: If there is an update the
|
||||
allStatuses.forEach((status) => {
|
||||
private removeRegisteredCommands(): void {
|
||||
this.registeredCommands.forEach((commandId) => {
|
||||
// @ts-ignore
|
||||
this.app.commands.removeCommand(
|
||||
`note-status:set-status-${status.name}`,
|
||||
);
|
||||
// @ts-ignore
|
||||
this.app.commands.removeCommand(
|
||||
`note-status:toggle-status-${status.name}`,
|
||||
);
|
||||
this.app.commands.removeCommand(`note-status:${commandId}`);
|
||||
});
|
||||
this.registeredCommands.clear();
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
// Remove existing commands
|
||||
this.removeQuickStatusCommands();
|
||||
this.registeredCommands.clear();
|
||||
// Remove all registered commands properly
|
||||
this.removeRegisteredCommands();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,8 +166,7 @@ export class GroupedDashboardView extends ItemView {
|
|||
key === "useCustomStatusesOnly" ||
|
||||
key === "customStatuses" ||
|
||||
key === "useMultipleStatuses" ||
|
||||
key === "strictStatuses" ||
|
||||
key === "excludeUnknownStatus"
|
||||
key === "strictStatuses"
|
||||
) {
|
||||
onDataChange();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,8 +151,7 @@ export class GroupedStatusView extends ItemView {
|
|||
key === "useCustomStatusesOnly" ||
|
||||
key === "customStatuses" ||
|
||||
key === "useMultipleStatuses" ||
|
||||
key === "strictStatuses" ||
|
||||
key === "excludeUnknownStatus"
|
||||
key === "strictStatuses"
|
||||
) {
|
||||
onDataChange();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -334,8 +334,7 @@ export class StatusDashboardView extends ItemView {
|
|||
key === "useCustomStatusesOnly" ||
|
||||
key === "customStatuses" ||
|
||||
key === "useMultipleStatuses" ||
|
||||
key === "strictStatuses" ||
|
||||
key === "excludeUnknownStatus"
|
||||
key === "strictStatuses"
|
||||
) {
|
||||
handleVaultChange();
|
||||
handleFileChange();
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.status-group-header {
|
||||
.status-group__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
|
@ -120,26 +120,39 @@
|
|||
background: var(--background-secondary-alt);
|
||||
border-radius: var(--radius-s);
|
||||
margin-bottom: var(--size-2-2);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
transition: background var(--anim-duration-fast) ease;
|
||||
}
|
||||
|
||||
.status-group-name {
|
||||
.status-group__header:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.status-group__name {
|
||||
text-transform: capitalize;
|
||||
font-weight: var(--font-medium);
|
||||
font-size: var(--font-ui-smaller);
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.status-group-count {
|
||||
padding: 1px var(--size-2-2);
|
||||
.status-group__count {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: var(--size-2-1) var(--size-2-2);
|
||||
background: var(--background-modifier-border);
|
||||
border-radius: var(--radius-s);
|
||||
font-size: var(--font-ui-smaller);
|
||||
color: var(--text-muted);
|
||||
font-weight: var(--font-medium);
|
||||
min-width: 20px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.status-group-items {
|
||||
.status-group__items {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
gap: var(--size-2-2);
|
||||
padding: 0 var(--size-2-1);
|
||||
}
|
||||
|
||||
.status-item {
|
||||
|
|
|
|||
|
|
@ -83,25 +83,57 @@
|
|||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: var(--radius-m);
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
transition: box-shadow var(--anim-duration-fast) ease;
|
||||
}
|
||||
|
||||
.grouped-status-group-header {
|
||||
.grouped-status-group:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.grouped-status-group__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: var(--size-4-2) var(--size-4-3);
|
||||
cursor: pointer;
|
||||
transition: background var(--anim-duration-fast) ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.grouped-status-group-header:hover {
|
||||
.grouped-status-group__header:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.grouped-status-group-info {
|
||||
.grouped-status-group__header:focus {
|
||||
outline: 2px solid var(--color-accent);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.grouped-status-group__status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--size-2-2);
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.grouped-status-group__template-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: var(--size-2-1) var(--size-2-2);
|
||||
background: var(--background-modifier-border);
|
||||
border-radius: var(--radius-s);
|
||||
font-size: var(--font-ui-smaller);
|
||||
color: var(--text-muted);
|
||||
font-weight: var(--font-medium);
|
||||
}
|
||||
|
||||
.grouped-status-group__info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--size-2-2);
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* Files List */
|
||||
|
|
|
|||
|
|
@ -256,24 +256,99 @@
|
|||
/* Status Group for Quick Commands */
|
||||
.status-group {
|
||||
margin-bottom: var(--size-4-4);
|
||||
padding: var(--size-4-3);
|
||||
background: var(--background-primary-alt);
|
||||
border-radius: var(--radius-m);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.status-group-header {
|
||||
.status-group__header {
|
||||
margin-bottom: var(--size-4-2);
|
||||
padding-bottom: var(--size-2-2);
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.status-group-title {
|
||||
.status-group__title {
|
||||
font-weight: var(--font-semibold);
|
||||
color: var(--text-normal);
|
||||
font-size: var(--font-ui-medium);
|
||||
}
|
||||
|
||||
.status-group-description {
|
||||
.status-group__description {
|
||||
font-size: var(--font-ui-smaller);
|
||||
color: var(--text-muted);
|
||||
margin-top: var(--size-2-1);
|
||||
line-height: var(--line-height-tight);
|
||||
}
|
||||
|
||||
.status-group-items {
|
||||
.status-group__items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--size-2-2);
|
||||
}
|
||||
|
||||
/* Status Selector for Quick Commands */
|
||||
.status-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--size-2-3) var(--size-4-2);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: var(--radius-m);
|
||||
background: var(--background-primary);
|
||||
cursor: pointer;
|
||||
transition: all var(--anim-duration-fast) ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.status-selector:hover {
|
||||
background: var(--background-modifier-hover);
|
||||
border-color: var(--background-modifier-border-hover);
|
||||
}
|
||||
|
||||
.status-selector--selected {
|
||||
background: var(--background-modifier-success);
|
||||
border-color: var(--interactive-success);
|
||||
}
|
||||
|
||||
.status-selector--selected:hover {
|
||||
background: var(--background-modifier-success-hover);
|
||||
}
|
||||
|
||||
.status-selector__content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.status-selector__status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--size-2-2);
|
||||
margin-bottom: var(--size-2-1);
|
||||
}
|
||||
|
||||
.status-selector__icon {
|
||||
font-size: var(--font-ui-medium);
|
||||
width: var(--size-4-3);
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status-selector__name {
|
||||
font-weight: var(--font-medium);
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.status-selector__description {
|
||||
font-size: var(--font-ui-smaller);
|
||||
color: var(--text-muted);
|
||||
line-height: var(--line-height-tight);
|
||||
}
|
||||
|
||||
.status-selector__checkbox {
|
||||
margin-left: var(--size-4-2);
|
||||
pointer-events: none;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Quick Commands Container */
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ export type PluginSettings = {
|
|||
useMultipleStatuses: boolean; // Whether to allow multiple statuses per note
|
||||
tagPrefix: string; // Prefix for the status tag (default: 'status')
|
||||
strictStatuses: boolean; // Whether to only show known statuses
|
||||
excludeUnknownStatus: boolean; // Whether to exclude files with unknown status from the status pane
|
||||
quickStatusCommands: string[];
|
||||
// Unknown status customization
|
||||
unknownStatusIcon: string; // Custom icon for unknown status
|
||||
|
|
|
|||
|
|
@ -84,6 +84,11 @@ Controls which predefined status sets are available.
|
|||
☐ Auto-hide status bar
|
||||
Hides when status is "unknown"
|
||||
Useful for clean interface when no status assigned
|
||||
|
||||
Custom Unknown Status:
|
||||
✅ Show custom icon for unknown status
|
||||
📝 Custom unknown icon: [❓]
|
||||
Customize the icon displayed for notes without status
|
||||
```
|
||||
|
||||
#### File Explorer Integration
|
||||
|
|
@ -95,17 +100,11 @@ Controls which predefined status sets are available.
|
|||
☐ Hide unknown status in file explorer
|
||||
Improves visual clarity by hiding ❓ icons
|
||||
Recommended for large vaults
|
||||
```
|
||||
|
||||
#### Status Pane Options
|
||||
|
||||
```
|
||||
☐ Default to compact view
|
||||
Starts status pane in dense layout mode
|
||||
|
||||
✅ Exclude unassigned notes from status pane
|
||||
Skips files with "unknown" status
|
||||
CRITICAL for performance with large vaults (>5000 notes)
|
||||
Icon Position: [Before name | After name]
|
||||
Configure where status icons appear in the file tree
|
||||
Before name: Shows status before filename
|
||||
After name: Shows status after filename (default)
|
||||
```
|
||||
|
||||
### Status Behavior
|
||||
|
|
@ -293,14 +292,6 @@ Ctrl+Shift+S → Change status of current note
|
|||
|
||||
### Performance Tuning
|
||||
|
||||
#### Large Vault Settings (5000+ notes)
|
||||
|
||||
```
|
||||
✅ Exclude unassigned notes from status pane
|
||||
✅ Hide unknown status in file explorer
|
||||
Items per page: 50 (reduce from default 100)
|
||||
```
|
||||
|
||||
#### Memory Optimization
|
||||
|
||||
```
|
||||
|
|
@ -308,18 +299,36 @@ Items per page: 50 (reduce from default 100)
|
|||
☐ Auto-hide status bar (reduce DOM updates)
|
||||
```
|
||||
|
||||
### Template-Based Status Scoping
|
||||
|
||||
#### Overview
|
||||
|
||||
```
|
||||
✅ Enable template-based filtering
|
||||
Scope statuses to specific note templates
|
||||
Organize status groups by note type
|
||||
```
|
||||
|
||||
#### Template Configuration
|
||||
|
||||
1. **Define note templates** in your vault
|
||||
2. **Associate statuses with templates** in settings
|
||||
3. **Filter status pane** by template type
|
||||
|
||||
**Example workflow**:
|
||||
|
||||
```
|
||||
Daily Notes Template → [active, completed, onHold]
|
||||
Project Template → [planning, inProgress, testing, live]
|
||||
Meeting Template → [scheduled, completed, followUp]
|
||||
```
|
||||
|
||||
#### Status Pane Filtering
|
||||
|
||||
- **Template dropdown** filters notes by template type
|
||||
- **Combined filtering** works with status and search filters
|
||||
- **Grouped view** organizes by template and status
|
||||
|
||||
### Import/Export Configuration
|
||||
|
||||
WIP
|
||||
|
||||
#### Export Settings
|
||||
|
||||
WIP
|
||||
|
||||
#### Import Process
|
||||
|
||||
WIP
|
||||
|
||||
#### Migration Between Vaults
|
||||
|
||||
WIP
|
||||
_This feature is planned for future releases._
|
||||
|
|
|
|||
|
|
@ -26,12 +26,13 @@ Welcome to the comprehensive documentation for the Note Status plugin for Obsidi
|
|||
|
||||
- ✅ Status assignment (active, on hold, completed, dropped)
|
||||
- ✅ Multiple statuses per note
|
||||
- ✅ File explorer integration
|
||||
- ✅ Status bar display
|
||||
- ✅ File explorer integration with configurable icon positioning
|
||||
- ✅ Status bar display with custom unknown status icons
|
||||
- ✅ Dropdown status selector
|
||||
- ✅ Dedicated status pane
|
||||
- ✅ Dedicated status pane with command palette access
|
||||
- ✅ Batch operations
|
||||
- ✅ Custom statuses and templates
|
||||
- ✅ Custom statuses with reorder controls and templates
|
||||
- ✅ Template-based status scoping and filtering
|
||||
|
||||
### Advanced Features
|
||||
|
||||
|
|
@ -84,4 +85,4 @@ We welcome contributions! See the [[Development Setup]] guide to get started.
|
|||
|
||||
---
|
||||
|
||||
_Last updated: [Current Date]_ _Plugin version: 1.0.12_
|
||||
_Last updated: July 20, 2025_ _Plugin version: 1.0.14_
|
||||
|
|
|
|||
|
|
@ -4,14 +4,6 @@ Optimize Note Status for large vaults (tested up to 40k notes).
|
|||
|
||||
## Quick Wins
|
||||
|
||||
### Essential Settings for 5k+ Notes
|
||||
|
||||
```
|
||||
✅ Exclude unassigned notes from status pane
|
||||
✅ Hide unknown status in file explorer
|
||||
Pagination: 50-100 items per page
|
||||
```
|
||||
|
||||
### Disable Heavy Features
|
||||
|
||||
```
|
||||
|
|
@ -24,7 +16,6 @@ Pagination: 50-100 items per page
|
|||
```json
|
||||
{
|
||||
"showStatusIconsInExplorer": false,
|
||||
"excludeUnknownStatus": true,
|
||||
"hideUnknownStatusInExplorer": true,
|
||||
"enabledTemplates": ["minimal"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,15 +82,6 @@ Enable a template for instant statuses:
|
|||
- Select multiple files for batch updates - 
|
||||

|
||||
|
||||
## Performance Setup (Large Vaults)
|
||||
|
||||
If you have 1000+ notes, set the settings:
|
||||
|
||||
```
|
||||
✅ Exclude unassigned notes from status pane
|
||||
✅ Hide unknown status in file explorer
|
||||
```
|
||||
|
||||
## Frontmatter Format
|
||||
|
||||
The plugin stores statuses in YAML frontmatter:
|
||||
|
|
|
|||
Loading…
Reference in a new issue