mirror of
https://github.com/devonthesofa/obsidian-note-status.git
synced 2026-07-22 05:45:04 +00:00
chore: improve UI
This commit is contained in:
parent
7dcac0a704
commit
1629944738
2 changed files with 36 additions and 166 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import React, { FC, memo, useEffect, useState } from "react";
|
||||
import React, { FC, memo } from "react";
|
||||
import { GroupedStatuses } from "@/types/noteStatus";
|
||||
import { StatusesInfoPopup } from "@/integrations/popups/statusesInfoPopupIntegration";
|
||||
|
||||
|
|
@ -13,20 +13,12 @@ interface EditorToolbarButtonProps {
|
|||
|
||||
export const EditorToolbarButton: FC<EditorToolbarButtonProps> = memo(
|
||||
({ statuses, onClick, unknownStatusConfig }) => {
|
||||
const [statusChanged, setStatusChanged] = useState(false);
|
||||
const statusEntries = Object.entries(statuses);
|
||||
const allStatuses = statusEntries.flatMap(
|
||||
([_, statusList]) => statusList,
|
||||
);
|
||||
const totalStatuses = allStatuses.length;
|
||||
|
||||
// Animate when status changes
|
||||
useEffect(() => {
|
||||
setStatusChanged(true);
|
||||
const timer = setTimeout(() => setStatusChanged(false), 600);
|
||||
return () => clearTimeout(timer);
|
||||
}, [statusEntries.length, allStatuses.map((s) => s.name).join(",")]);
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
StatusesInfoPopup.open(statuses);
|
||||
};
|
||||
|
|
@ -37,27 +29,15 @@ export const EditorToolbarButton: FC<EditorToolbarButtonProps> = memo(
|
|||
|
||||
const getPrimaryStatus = () => allStatuses[0];
|
||||
|
||||
const containerClasses = [
|
||||
"editor-toolbar-button",
|
||||
totalStatuses === 0
|
||||
? "editor-toolbar-button--no-status"
|
||||
: "editor-toolbar-button--has-status",
|
||||
totalStatuses > 1 ? "editor-toolbar-button--multiple" : "",
|
||||
statusChanged ? "editor-toolbar-button--status-changed" : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
// No status state
|
||||
if (totalStatuses === 0) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={containerClasses}
|
||||
className="clickable-icon"
|
||||
onClick={onClick}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
title="No status assigned - click to add"
|
||||
aria-label="Add status to note"
|
||||
>
|
||||
<span
|
||||
|
|
@ -66,9 +46,6 @@ export const EditorToolbarButton: FC<EditorToolbarButtonProps> = memo(
|
|||
>
|
||||
{unknownStatusConfig.icon}
|
||||
</span>
|
||||
<span className="editor-toolbar-button__text">
|
||||
Add Status
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
|
@ -80,22 +57,14 @@ export const EditorToolbarButton: FC<EditorToolbarButtonProps> = memo(
|
|||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={containerClasses}
|
||||
className="clickable-icon"
|
||||
onClick={onClick}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
title={`Status: ${primaryStatus.name} - click to change`}
|
||||
aria-label={`Current status: ${primaryStatus.name}. Click to change.`}
|
||||
style={
|
||||
{
|
||||
"--status-color":
|
||||
primaryStatus.color ||
|
||||
"var(--interactive-accent)",
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="editor-toolbar-button__icon"
|
||||
className="editor-toolbar-button__icon editor-toolbar-button__icon--has-status"
|
||||
style={{
|
||||
color:
|
||||
primaryStatus.color ||
|
||||
|
|
@ -104,9 +73,6 @@ export const EditorToolbarButton: FC<EditorToolbarButtonProps> = memo(
|
|||
>
|
||||
{primaryStatus.icon || "📝"}
|
||||
</span>
|
||||
<span className="editor-toolbar-button__text">
|
||||
{primaryStatus.name}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
|
@ -115,22 +81,15 @@ export const EditorToolbarButton: FC<EditorToolbarButtonProps> = memo(
|
|||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={containerClasses}
|
||||
className="clickable-icon"
|
||||
onClick={onClick}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
title={`${totalStatuses} statuses: ${allStatuses.map((s) => s.name).join(", ")} - click to change`}
|
||||
aria-label={`${totalStatuses} statuses assigned. Click to change.`}
|
||||
style={
|
||||
{
|
||||
"--status-color":
|
||||
primaryStatus.color || "var(--interactive-accent)",
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<span className="editor-toolbar-button__icon-stack">
|
||||
<div className="editor-toolbar-button__icon-container">
|
||||
<span
|
||||
className="editor-toolbar-button__icon"
|
||||
className="editor-toolbar-button__icon editor-toolbar-button__icon--has-status"
|
||||
style={{
|
||||
color:
|
||||
primaryStatus.color ||
|
||||
|
|
@ -142,10 +101,7 @@ export const EditorToolbarButton: FC<EditorToolbarButtonProps> = memo(
|
|||
<span className="editor-toolbar-button__counter">
|
||||
{totalStatuses}
|
||||
</span>
|
||||
</span>
|
||||
<span className="editor-toolbar-button__text">
|
||||
{totalStatuses} Status{totalStatuses === 1 ? "" : "es"}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,75 +1,46 @@
|
|||
/* Editor Toolbar Button - Obsidian-integrated icon button */
|
||||
.editor-toolbar-button {
|
||||
/* 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;
|
||||
justify-content: center;
|
||||
gap: var(--size-2-1);
|
||||
padding: var(--size-2-1);
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--radius-s);
|
||||
font-size: var(--font-ui-smaller);
|
||||
font-weight: var(--font-medium);
|
||||
color: var(--icon-color, var(--text-muted));
|
||||
cursor: pointer;
|
||||
transition: all var(--anim-duration-fast) ease;
|
||||
position: relative;
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
opacity: var(--icon-opacity);
|
||||
outline: none;
|
||||
margin: 0 var(--size-2-1);
|
||||
}
|
||||
|
||||
.editor-toolbar-button:hover {
|
||||
background: transparent;
|
||||
border-color: var(--background-modifier-border);
|
||||
opacity: var(--icon-opacity-hover);
|
||||
color: var(--icon-color-hover, var(--text-normal));
|
||||
}
|
||||
|
||||
.editor-toolbar-button:active {
|
||||
background: var(--background-modifier-hover);
|
||||
border-color: var(--background-modifier-border-hover);
|
||||
opacity: var(--icon-opacity-active);
|
||||
}
|
||||
|
||||
.editor-toolbar-button:focus-visible {
|
||||
outline: 2px solid var(--interactive-accent);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
/* Icon styling */
|
||||
.editor-toolbar-button__icon {
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 14px;
|
||||
}
|
||||
|
||||
/* Text styling - Hidden by default, shown on hover */
|
||||
.editor-toolbar-button__text {
|
||||
/* Hidden state */
|
||||
.note-status-editor-toolbar-badge--hidden {
|
||||
display: none;
|
||||
white-space: nowrap;
|
||||
line-height: 1.2;
|
||||
font-size: var(--font-ui-smaller);
|
||||
font-weight: var(--font-medium);
|
||||
margin-left: var(--size-2-1);
|
||||
}
|
||||
|
||||
/* Icon stack for multiple statuses */
|
||||
.editor-toolbar-button__icon-stack {
|
||||
/* 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: -2px;
|
||||
right: -2px;
|
||||
top: -4px;
|
||||
right: -6px;
|
||||
min-width: 12px;
|
||||
height: 12px;
|
||||
padding: 0 2px;
|
||||
|
|
@ -84,60 +55,3 @@
|
|||
line-height: 1;
|
||||
border: 1px solid var(--background-primary);
|
||||
}
|
||||
|
||||
/* Status variants */
|
||||
.editor-toolbar-button--has-status {
|
||||
color: var(--status-color, var(--interactive-accent));
|
||||
}
|
||||
|
||||
.editor-toolbar-button--has-status:hover {
|
||||
color: var(--status-color, var(--interactive-accent));
|
||||
}
|
||||
|
||||
.editor-toolbar-button--no-status {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.editor-toolbar-button--no-status:hover {
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
/* Multiple statuses styling */
|
||||
.editor-toolbar-button--multiple {
|
||||
color: var(--status-color, var(--interactive-accent));
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Status change animation */
|
||||
@keyframes status-change-pulse {
|
||||
0% {
|
||||
opacity: var(--icon-opacity);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: var(--icon-opacity);
|
||||
}
|
||||
}
|
||||
|
||||
.editor-toolbar-button--status-changed {
|
||||
animation: status-change-pulse 0.6s ease-out;
|
||||
}
|
||||
|
||||
/* Show text on hover for better UX */
|
||||
.editor-toolbar-button:hover .editor-toolbar-button__text {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue