Merge pull request #100 from devonthesofa/feature/improve-status-group

improve status group UI
This commit is contained in:
Aleix Soler 2026-03-19 19:15:01 +01:00 committed by GitHub
commit bed56422aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 96 additions and 84 deletions

View file

@ -1,7 +1,5 @@
import React, { useCallback } from "react";
import { FileItem } from "../GroupedStatusView";
import { SelectableListItem } from "../../atoms/SelectableListItem";
interface FileListProps {
files: FileItem[];
groupKey: string;
@ -48,21 +46,23 @@ export const FileList = ({
<div className="grouped-status-files">
<div className="grouped-status-files-list" onScroll={handleScroll}>
{visibleFiles.map((file) => (
<SelectableListItem
<div
key={file.id}
className="tree-item nav-file grouped-status-file-item"
onClick={() => handleFileClick(file)}
className="grouped-status-file-item"
title={file.path}
>
<div>
<span className="grouped-status-file-name">
{file.name}
</span>
<span className="grouped-status-file-path">
{file.path}
</span>
<div className="tree-item-self is-clickable nav-file-title">
<div className="tree-item-inner nav-file-title-content grouped-status-file-content">
<div className="grouped-status-file-name">
{file.name}
</div>
<div className="grouped-status-file-path">
{file.path}
</div>
</div>
</div>
</SelectableListItem>
</div>
))}
{hasMoreItems && (

View file

@ -46,12 +46,12 @@ export const StatusGroup = ({
}, [onToggle]);
return (
<div className="grouped-status-group">
<div className="grouped-status-group tree-item">
<div
className="grouped-status-group__header"
className="grouped-status-group__header tree-item-self is-clickable"
onClick={handleToggle}
>
<div className="grouped-status-group__status">
<div className="tree-item-inner grouped-status-group__status">
<StatusDisplay
status={
{
@ -78,14 +78,16 @@ export const StatusGroup = ({
</div>
{isExpanded && (
<FileList
files={files}
groupKey={groupKey}
loadedCount={loadedCount}
onFileClick={onFileClick}
onScroll={onScroll}
onLoadMore={onLoadMore}
/>
<div className="tree-item-children">
<FileList
files={files}
groupKey={groupKey}
loadedCount={loadedCount}
onFileClick={onFileClick}
onScroll={onScroll}
onLoadMore={onLoadMore}
/>
</div>
)}
</div>
);

View file

@ -1,4 +1,4 @@
import React, { useCallback } from "react";
import React, { useCallback, useMemo } from "react";
import { GroupLabel } from "@/components/atoms/GroupLabel";
import { CollapsibleCounter } from "@/components/atoms/CollapsibleCounter";
import { FilesByStatus, FileItem, StatusItem } from "../GroupedStatusView";
@ -51,6 +51,11 @@ export const TagSection = ({
[onToggleFiles],
);
const statusOrder = useMemo(
() => Array.from(statusMap.keys()),
[statusMap],
);
return (
<div className="grouped-status-tag-section">
<div className="grouped-status-tag-header" onClick={handleToggle}>
@ -64,32 +69,38 @@ export const TagSection = ({
{isExpanded && (
<div className="grouped-status-tag-content">
{Object.entries(statusGroups).map(([statusName, files]) => {
if (files.length === 0) return null;
{Object.entries(statusGroups)
.sort(
([statusA], [statusB]) =>
statusOrder.indexOf(statusA) -
statusOrder.indexOf(statusB),
)
.map(([statusName, files]) => {
if (files.length === 0) return null;
const status = statusMap.get(statusName);
if (!status) return null;
const status = statusMap.get(statusName);
if (!status) return null;
const groupKey = `${tag}-${statusName}`;
const filesExpanded = expandedFiles.has(groupKey);
const loadedCount = getLoadedCount(groupKey);
const groupKey = `${tag}-${statusName}`;
const filesExpanded = expandedFiles.has(groupKey);
const loadedCount = getLoadedCount(groupKey);
return (
<StatusGroup
key={statusName}
statusName={statusName}
status={status}
files={files}
tag={tag}
isExpanded={filesExpanded}
loadedCount={loadedCount}
onToggle={() => handleToggleFiles(groupKey)}
onFileClick={onFileClick}
onScroll={onScroll}
onLoadMore={onLoadMore}
/>
);
})}
return (
<StatusGroup
key={statusName}
statusName={statusName}
status={status}
files={files}
tag={tag}
isExpanded={filesExpanded}
loadedCount={loadedCount}
onToggle={() => handleToggleFiles(groupKey)}
onFileClick={onFileClick}
onScroll={onScroll}
onLoadMore={onLoadMore}
/>
);
})}
</div>
)}
</div>

File diff suppressed because one or more lines are too long

View file

@ -78,25 +78,18 @@
/* Status Group */
.grouped-status-group {
margin-bottom: var(--size-4-2);
background: var(--background-primary);
border: 1px solid var(--background-modifier-border);
margin-bottom: 2px;
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: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);
padding: 4px 8px;
cursor: pointer;
border-radius: var(--radius-s);
transition: background var(--anim-duration-fast) ease;
position: relative;
}
@ -105,8 +98,8 @@
background: var(--background-modifier-hover);
}
.grouped-status-group__header:focus {
outline: 2px solid var(--color-accent);
.grouped-status-group__header:focus-visible {
outline: 2px solid var(--interactive-accent);
outline-offset: -2px;
}
@ -138,40 +131,46 @@
/* Files List */
.grouped-status-files {
background: var(--background-secondary);
border-top: 1px solid var(--background-modifier-border);
margin-bottom: var(--size-2-2);
}
.grouped-status-files-list {
max-height: 300px;
max-height: 400px;
overflow-y: auto;
}
.grouped-status-file-item {
padding: var(--size-2-3) var(--size-4-3);
cursor: pointer;
transition: background var(--anim-duration-fast) ease;
border-bottom: 1px solid var(--background-modifier-border-hover);
border-radius: var(--radius-s);
margin-top: 1px;
}
.grouped-status-file-item:hover {
.grouped-status-file-item:hover .tree-item-self {
background: var(--background-modifier-hover);
}
.grouped-status-file-item:last-child {
border-bottom: none;
.grouped-status-file-content {
display: flex;
flex-direction: column;
width: 100%;
}
.grouped-status-file-name {
font-weight: var(--font-medium);
color: var(--text-normal);
margin-bottom: 2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.grouped-status-file-path {
font-size: var(--font-ui-small);
font-size: var(--font-ui-smaller);
color: var(--text-muted);
opacity: 0.8;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Load More */

View file

@ -2,18 +2,18 @@ import { NoteStatus } from "./noteStatus";
export type StatusFrontmatterMapping =
| {
id: string;
scope: "template";
templateId: string;
frontmatterKeys: string[];
}
id: string;
scope: "template";
templateId: string;
frontmatterKeys: string[];
}
| {
id: string;
scope: "status";
templateId?: string;
statusName: string;
frontmatterKeys: string[];
};
id: string;
scope: "status";
templateId?: string;
statusName: string;
frontmatterKeys: string[];
};
export interface StatusTemplate {
id: string;
@ -37,9 +37,9 @@ export type SyncGroup =
export type PluginSettings = {
fileExplorerIconPosition:
| "absolute-right"
| "file-name-left"
| "file-name-right";
| "absolute-right"
| "file-name-left"
| "file-name-right";
fileExplorerIconFrame: "always" | "never";
fileExplorerIconColorMode: "status" | "theme";
statusColors: Record<string, string>;