-
+
+
+ {templateId && (
+
+ {templateId}
+
+ )}
+
void;
getAvailableStatuses: () => StatusItem[];
+ getAvailableStatusesWithTemplateInfo: () => NoteStatus[];
};
const GroupedDataContext = createContext(
@@ -52,8 +54,10 @@ type GroupedDataProviderProps = {
onFileClick: (file: FileItem) => void;
subscribeToEvents: (onDataChange: () => void) => () => void;
getAvailableStatuses: () => StatusItem[];
+ getAvailableStatusesWithTemplateInfo: () => NoteStatus[];
searchFilter: string;
noteNameFilter: string;
+ templateFilter: string;
};
export const GroupedDataProvider = ({
@@ -63,8 +67,10 @@ export const GroupedDataProvider = ({
onFileClick,
subscribeToEvents,
getAvailableStatuses,
+ getAvailableStatusesWithTemplateInfo,
searchFilter,
noteNameFilter,
+ templateFilter,
}: GroupedDataProviderProps) => {
const { groupedData, filteredData, isLoading, loadData } = useGroupedData({
getAllFiles,
@@ -72,6 +78,7 @@ export const GroupedDataProvider = ({
subscribeToEvents,
searchFilter,
noteNameFilter,
+ templateFilter,
});
const { getLoadedCount, loadMoreItems, handleScroll } = usePagination();
@@ -93,6 +100,7 @@ export const GroupedDataProvider = ({
toggleFiles,
onFileClick,
getAvailableStatuses,
+ getAvailableStatusesWithTemplateInfo,
};
return (
diff --git a/components/GroupedStatusView/hooks/useGroupedData.ts b/components/GroupedStatusView/hooks/useGroupedData.ts
index 689070f..3978b6a 100644
--- a/components/GroupedStatusView/hooks/useGroupedData.ts
+++ b/components/GroupedStatusView/hooks/useGroupedData.ts
@@ -7,6 +7,7 @@ export type UseGroupedDataProps = {
subscribeToEvents: (onDataChange: () => void) => () => void;
searchFilter: string;
noteNameFilter: string;
+ templateFilter: string;
};
export const useGroupedData = ({
@@ -15,6 +16,7 @@ export const useGroupedData = ({
subscribeToEvents,
searchFilter,
noteNameFilter,
+ templateFilter,
}: UseGroupedDataProps) => {
const [groupedData, setGroupedData] = useState({});
const [isLoading, setIsLoading] = useState(true);
@@ -43,7 +45,12 @@ export const useGroupedData = ({
}, [loadData, subscribeToEvents]);
const filteredData = useMemo(() => {
- if (!searchFilter.trim() && !noteNameFilter.trim()) return groupedData;
+ if (
+ !searchFilter.trim() &&
+ !noteNameFilter.trim() &&
+ !templateFilter.trim()
+ )
+ return groupedData;
const filtered: GroupedByStatus = {};
const searchLower = searchFilter.toLowerCase();
@@ -52,6 +59,18 @@ export const useGroupedData = ({
Object.entries(groupedData).forEach(([tag, statusGroups]) => {
filtered[tag] = {};
Object.entries(statusGroups).forEach(([statusName, files]) => {
+ // Filter by template if templateFilter is provided
+ if (templateFilter.trim()) {
+ // Check if statusName contains the template (scoped: "template:status")
+ const statusTemplate = statusName.includes(":")
+ ? statusName.split(":", 2)[0]
+ : "";
+
+ if (statusTemplate !== templateFilter) {
+ return; // Skip this status group if it doesn't match the template filter
+ }
+ }
+
let matchingFiles = files;
// Filter by status/tag if searchFilter is provided
@@ -79,7 +98,7 @@ export const useGroupedData = ({
});
return filtered;
- }, [groupedData, searchFilter, noteNameFilter]);
+ }, [groupedData, searchFilter, noteNameFilter, templateFilter]);
return {
groupedData,
diff --git a/integrations/views/grouped-dashboard-view.tsx b/integrations/views/grouped-dashboard-view.tsx
index d82a11b..335f432 100644
--- a/integrations/views/grouped-dashboard-view.tsx
+++ b/integrations/views/grouped-dashboard-view.tsx
@@ -137,6 +137,10 @@ export class GroupedDashboardView extends ItemView {
return statuses.map(this.convertStatusToStatusItem);
};
+ private getAvailableStatusesWithTemplateInfo = () => {
+ return BaseNoteStatusService.getAllAvailableStatuses();
+ };
+
private handleFileClick = (file: FileItem) => {
const tFile = BaseNoteStatusService.app.vault.getAbstractFileByPath(
file.path,
@@ -201,6 +205,9 @@ export class GroupedDashboardView extends ItemView {
onFileClick={this.handleFileClick}
subscribeToEvents={this.subscribeToEvents}
getAvailableStatuses={this.getAvailableStatuses}
+ getAvailableStatusesWithTemplateInfo={
+ this.getAvailableStatusesWithTemplateInfo
+ }
/>,
);
}
diff --git a/integrations/views/grouped-status-view.tsx b/integrations/views/grouped-status-view.tsx
index 274cb5d..df267dc 100644
--- a/integrations/views/grouped-status-view.tsx
+++ b/integrations/views/grouped-status-view.tsx
@@ -122,6 +122,10 @@ export class GroupedStatusView extends ItemView {
return statuses.map(this.convertStatusToStatusItem);
};
+ private getAvailableStatusesWithTemplateInfo = () => {
+ return BaseNoteStatusService.getAllAvailableStatuses();
+ };
+
private handleFileClick = (file: FileItem) => {
const tFile = BaseNoteStatusService.app.vault.getAbstractFileByPath(
file.path,
@@ -186,6 +190,9 @@ export class GroupedStatusView extends ItemView {
onFileClick={this.handleFileClick}
subscribeToEvents={this.subscribeToEvents}
getAvailableStatuses={this.getAvailableStatuses}
+ getAvailableStatusesWithTemplateInfo={
+ this.getAvailableStatusesWithTemplateInfo
+ }
/>,
);
}
diff --git a/styles/components/grouped-view.css b/styles/components/grouped-view.css
index 2b2f16b..e8c5b0e 100644
--- a/styles/components/grouped-view.css
+++ b/styles/components/grouped-view.css
@@ -194,3 +194,67 @@
.grouped-status-files-list::-webkit-scrollbar-thumb:hover {
background: var(--scrollbar-active-bg);
}
+
+/* Template Filter (BEM) */
+.grouped-status-filters__template {
+ display: flex;
+ flex-direction: column;
+ gap: var(--size-2-1);
+}
+
+.grouped-status-filters__template-select {
+ width: 100%;
+ padding: var(--size-2-2) var(--size-2-3);
+ border: 1px solid var(--background-modifier-border);
+ border-radius: var(--radius-s);
+ background: var(--background-primary);
+ color: var(--text-normal);
+ font-size: var(--font-ui-small);
+ cursor: pointer;
+}
+
+.grouped-status-filters__template-select:focus {
+ outline: none;
+ border-color: var(--interactive-accent);
+ box-shadow: 0 0 0 2px var(--background-modifier-accent);
+}
+
+.grouped-status-filters__note {
+ display: flex;
+ flex-direction: column;
+ gap: var(--size-2-1);
+}
+
+.grouped-status-filters__note-input {
+ width: 100%;
+ padding: var(--size-2-2) var(--size-2-3);
+ border: 1px solid var(--background-modifier-border);
+ border-radius: var(--radius-s);
+ background: var(--background-primary);
+ color: var(--text-normal);
+ font-size: var(--font-ui-small);
+}
+
+.grouped-status-filters__note-input:focus {
+ outline: none;
+ border-color: var(--interactive-accent);
+ box-shadow: 0 0 0 2px var(--background-modifier-accent);
+}
+
+/* Template Badge (BEM) */
+.grouped-status-group__status {
+ display: flex;
+ align-items: center;
+ gap: var(--size-2-2);
+}
+
+.grouped-status-group__template-badge {
+ background: var(--background-modifier-border);
+ color: var(--text-muted);
+ padding: var(--size-2-1) var(--size-2-2);
+ border-radius: var(--radius-s);
+ font-size: var(--font-ui-smaller);
+ font-weight: var(--font-medium);
+ text-transform: capitalize;
+ white-space: nowrap;
+}