style: redesign subtask and notes inline UI
- Subtasks: slide-in animation, left border accent, hover highlights, mini progress bar in indicator badge, scale effect on checkbox hover - Notes: slide-in animation, cleaner toolbar with SVG icons instead of emoji, proper dark mode support, focus ring on editor, max-height cap - Both use CSS variables for consistent theming v1.40.1 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
85982f06a5
commit
2d386362ca
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "my-weekly-todo-list",
|
"name": "my-weekly-todo-list",
|
||||||
"version": "1.40.0",
|
"version": "1.40.1",
|
||||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -772,24 +772,34 @@ h3 {
|
|||||||
/* Inline Notes */
|
/* Inline Notes */
|
||||||
.weekly-notes-inline {
|
.weekly-notes-inline {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 0.5rem;
|
margin-top: 6px;
|
||||||
padding-left: 0;
|
padding: 0;
|
||||||
padding-right: 0.5rem;
|
animation: notesSlideIn 0.2s ease-out;
|
||||||
|
}
|
||||||
|
@keyframes notesSlideIn {
|
||||||
|
from { opacity: 0; transform: translateY(-4px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.weekly-notes-editor-inline {
|
.weekly-notes-editor-inline {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 80px;
|
min-height: 60px;
|
||||||
padding: 0.5rem;
|
max-height: 200px;
|
||||||
border: 1px solid #ddd; /* Light border for editor */
|
padding: 8px 10px;
|
||||||
border-radius: 4px;
|
border: 1px solid var(--weekly-border, #e5e7eb);
|
||||||
|
border-radius: 6px;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: 0.875rem;
|
font-size: 0.8rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: var(--weekly-text);
|
color: var(--weekly-text);
|
||||||
background: #fdfdfd;
|
background: var(--weekly-bg, #fff);
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
}
|
||||||
|
.dark-mode .weekly-notes-editor-inline {
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
border-color: rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Floating Notes Popup */
|
/* Floating Notes Popup */
|
||||||
@ -868,7 +878,10 @@ h3 {
|
|||||||
|
|
||||||
.weekly-notes-editor-inline:focus {
|
.weekly-notes-editor-inline:focus {
|
||||||
border-color: var(--weekly-teal);
|
border-color: var(--weekly-teal);
|
||||||
background: #fff;
|
box-shadow: 0 0 0 2px rgba(0, 154, 154, 0.1);
|
||||||
|
}
|
||||||
|
.dark-mode .weekly-notes-editor-inline:focus {
|
||||||
|
box-shadow: 0 0 0 2px rgba(0, 154, 154, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rolling Indicator */
|
/* Rolling Indicator */
|
||||||
@ -931,12 +944,14 @@ h3 {
|
|||||||
.notes-toolbar {
|
.notes-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 2px;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 4px;
|
||||||
padding: 0.25rem 0.5rem;
|
padding: 3px 4px;
|
||||||
background: #f8f8f8;
|
background: var(--weekly-settings-toggle-bg, #f3f4f6);
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
border: 1px solid #eee;
|
}
|
||||||
|
.dark-mode .notes-toolbar {
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
.notes-toolbar-btn {
|
.notes-toolbar-btn {
|
||||||
@ -944,19 +959,23 @@ h3 {
|
|||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--weekly-text-light);
|
color: var(--weekly-text-light);
|
||||||
font-size: 0.85rem;
|
font-size: 0.75rem;
|
||||||
padding: 2px 4px;
|
padding: 3px 7px;
|
||||||
border-radius: 3px;
|
border-radius: 4px;
|
||||||
min-width: 20px;
|
min-width: 24px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
transition: background 0.1s, color 0.1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notes-toolbar-btn:hover {
|
.notes-toolbar-btn:hover {
|
||||||
background: rgba(0,0,0,0.05);
|
background: var(--weekly-bg, #fff);
|
||||||
color: var(--weekly-text);
|
color: var(--weekly-text);
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
.dark-mode .notes-toolbar-btn:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Action Buttons Styling - Float above task on hover */
|
/* Action Buttons Styling - Float above task on hover */
|
||||||
@ -1051,21 +1070,37 @@ h3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Sub-tasks */
|
/* Sub-tasks */
|
||||||
|
/* Subtask list — animated expand/collapse */
|
||||||
.subtask-list {
|
.subtask-list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0.125rem 0 0.125rem 1.25rem;
|
padding: 4px 0 4px 12px;
|
||||||
margin: 0;
|
margin: 2px 0 0 0;
|
||||||
|
border-left: 2px solid var(--weekly-border, #e5e7eb);
|
||||||
|
margin-left: 6px;
|
||||||
|
animation: subtaskSlideIn 0.2s ease-out;
|
||||||
|
}
|
||||||
|
@keyframes subtaskSlideIn {
|
||||||
|
from { opacity: 0; transform: translateY(-4px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtask-item {
|
.subtask-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.375rem;
|
gap: 6px;
|
||||||
padding: 0.125rem 0;
|
padding: 3px 6px 3px 4px;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8rem;
|
||||||
color: var(--weekly-text);
|
color: var(--weekly-text);
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: background 0.1s;
|
||||||
|
}
|
||||||
|
.subtask-item:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.03);
|
||||||
|
}
|
||||||
|
.dark-mode .subtask-item:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
}
|
}
|
||||||
.subtask-item:active {
|
.subtask-item:active {
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
@ -1073,7 +1108,7 @@ h3 {
|
|||||||
|
|
||||||
.subtask-item.completed .subtask-title {
|
.subtask-item.completed .subtask-title {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
opacity: 0.5;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtask-checkbox {
|
.subtask-checkbox {
|
||||||
@ -1085,12 +1120,12 @@ h3 {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
transition: color 0.15s, transform 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtask-checkbox:hover {
|
.subtask-checkbox:hover {
|
||||||
color: var(--weekly-teal);
|
color: var(--weekly-teal);
|
||||||
|
transform: scale(1.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtask-item.completed .subtask-checkbox {
|
.subtask-item.completed .subtask-checkbox {
|
||||||
color: var(--weekly-teal);
|
color: var(--weekly-teal);
|
||||||
}
|
}
|
||||||
@ -1102,8 +1137,8 @@ h3 {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
transition: color 0.1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtask-title:hover {
|
.subtask-title:hover {
|
||||||
color: var(--weekly-teal);
|
color: var(--weekly-teal);
|
||||||
}
|
}
|
||||||
@ -1113,7 +1148,7 @@ h3 {
|
|||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
outline: none;
|
outline: none;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8rem;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
color: var(--weekly-text);
|
color: var(--weekly-text);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@ -1122,25 +1157,28 @@ h3 {
|
|||||||
.subtask-delete-btn {
|
.subtask-delete-btn {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0.125rem;
|
padding: 2px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--weekly-text-muted, #999);
|
color: var(--weekly-text-muted, #999);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.15s;
|
transition: opacity 0.15s, color 0.15s;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtask-item:hover .subtask-delete-btn {
|
.subtask-item:hover .subtask-delete-btn {
|
||||||
opacity: 1;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtask-delete-btn:hover {
|
.subtask-delete-btn:hover {
|
||||||
color: #e53e3e;
|
color: #ef4444;
|
||||||
|
opacity: 1 !important;
|
||||||
|
background: rgba(239, 68, 68, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtask-add-row {
|
.subtask-add-row {
|
||||||
padding: 0.125rem 0 0.25rem 1.25rem;
|
padding: 2px 0 4px 12px;
|
||||||
|
margin-left: 6px;
|
||||||
|
border-left: 2px solid var(--weekly-border, #e5e7eb);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtask-add-input {
|
.subtask-add-input {
|
||||||
@ -1148,15 +1186,15 @@ h3 {
|
|||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
outline: none;
|
outline: none;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8rem;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
color: var(--weekly-text);
|
color: var(--weekly-text);
|
||||||
padding: 0.125rem 0;
|
padding: 2px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtask-add-input::placeholder {
|
.subtask-add-input::placeholder {
|
||||||
color: var(--weekly-text-muted, #999);
|
color: var(--weekly-text-muted, #999);
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Task Input */
|
/* Task Input */
|
||||||
|
|||||||
@ -8943,6 +8943,7 @@ function TaskItem({
|
|||||||
const total = task.subTasks!.length;
|
const total = task.subTasks!.length;
|
||||||
const allDone = completed === total;
|
const allDone = completed === total;
|
||||||
const expanded = isSubTasksOpen || isSubTaskInputOpen;
|
const expanded = isSubTasksOpen || isSubTaskInputOpen;
|
||||||
|
const pct = total > 0 ? (completed / total) * 100 : 0;
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
@ -8954,25 +8955,46 @@ function TaskItem({
|
|||||||
style={{
|
style={{
|
||||||
display: "inline-flex",
|
display: "inline-flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: "3px",
|
gap: "4px",
|
||||||
padding: "2px 7px",
|
padding: "2px 8px 2px 6px",
|
||||||
borderRadius: "10px",
|
borderRadius: "12px",
|
||||||
background: expanded ? "rgba(99, 102, 241, 0.15)" : allDone ? "rgba(34, 197, 94, 0.15)" : "rgba(0,0,0,0.08)",
|
background: "transparent",
|
||||||
color: expanded ? "#6366f1" : allDone ? "#22c55e" : "#555",
|
color: allDone ? "var(--weekly-teal, #0d9488)" : "var(--weekly-text-light, #9ca3af)",
|
||||||
border: expanded ? "1px solid rgba(99, 102, 241, 0.3)" : allDone ? "1px solid rgba(34, 197, 94, 0.3)" : "1px solid rgba(0,0,0,0.12)",
|
border: "none",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
fontSize: "0.7rem",
|
fontSize: "0.7rem",
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
lineHeight: 1,
|
lineHeight: 1,
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
marginTop: "2px",
|
transition: "color 0.15s",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<svg viewBox="0 0 24 24" width="10" height="10" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" style={{ transform: expanded ? "rotate(90deg)" : "rotate(0deg)", transition: "transform 0.2s" }}>
|
<svg viewBox="0 0 24 24" width="10" height="10" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ transform: expanded ? "rotate(90deg)" : "rotate(0deg)", transition: "transform 0.2s" }}>
|
||||||
<polyline points="9 18 15 12 9 6" />
|
<polyline points="9 18 15 12 9 6" />
|
||||||
</svg>
|
</svg>
|
||||||
{completed}/{total}
|
{/* Mini progress bar */}
|
||||||
|
<span style={{
|
||||||
|
display: "inline-block",
|
||||||
|
width: "20px",
|
||||||
|
height: "3px",
|
||||||
|
borderRadius: "2px",
|
||||||
|
background: "var(--weekly-border, #e5e7eb)",
|
||||||
|
position: "relative",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}>
|
||||||
|
<span style={{
|
||||||
|
position: "absolute",
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
height: "100%",
|
||||||
|
width: `${pct}%`,
|
||||||
|
borderRadius: "2px",
|
||||||
|
background: allDone ? "var(--weekly-teal, #0d9488)" : "#6366f1",
|
||||||
|
transition: "width 0.3s ease",
|
||||||
|
}} />
|
||||||
|
</span>
|
||||||
|
<span style={{ opacity: 0.8 }}>{completed}/{total}</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
@ -8989,14 +9011,15 @@ function TaskItem({
|
|||||||
style={{
|
style={{
|
||||||
display: "inline-flex",
|
display: "inline-flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
padding: "2px 4px",
|
gap: "2px",
|
||||||
borderRadius: "3px",
|
padding: "2px 5px",
|
||||||
background: isNotesOpen ? "rgba(245, 158, 11, 0.12)" : "rgba(0,0,0,0.05)",
|
borderRadius: "4px",
|
||||||
color: isNotesOpen ? "#f59e0b" : "#888",
|
background: isNotesOpen ? "rgba(245, 158, 11, 0.1)" : "transparent",
|
||||||
|
color: isNotesOpen ? "#f59e0b" : "var(--weekly-text-muted, #999)",
|
||||||
border: "none",
|
border: "none",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
lineHeight: 1,
|
lineHeight: 1,
|
||||||
marginTop: "2px",
|
transition: "background 0.15s, color 0.15s",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
<svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
@ -9005,6 +9028,9 @@ function TaskItem({
|
|||||||
<line x1="16" y1="13" x2="8" y2="13" />
|
<line x1="16" y1="13" x2="8" y2="13" />
|
||||||
<line x1="16" y1="17" x2="8" y2="17" />
|
<line x1="16" y1="17" x2="8" y2="17" />
|
||||||
</svg>
|
</svg>
|
||||||
|
<svg viewBox="0 0 24 24" width="8" height="8" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ transform: isNotesOpen ? "rotate(90deg)" : "rotate(0deg)", transition: "transform 0.2s" }}>
|
||||||
|
<polyline points="9 18 15 12 9 6" />
|
||||||
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -9253,50 +9279,15 @@ function TaskItem({
|
|||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
<div className="notes-toolbar">
|
<div className="notes-toolbar">
|
||||||
<button
|
<button className="notes-toolbar-btn" onClick={() => insertMarkdown("**", "**")} title="Bold" style={{ fontWeight: 700 }}>B</button>
|
||||||
className="notes-toolbar-btn"
|
<button className="notes-toolbar-btn" onClick={() => insertMarkdown("*", "*")} title="Italic" style={{ fontStyle: "italic" }}>I</button>
|
||||||
onClick={() => insertMarkdown("**", "**")}
|
<button className="notes-toolbar-btn" onClick={() => insertMarkdown("[", "](url)")} title="Link">
|
||||||
title="Bold"
|
<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
|
||||||
>
|
|
||||||
B
|
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button className="notes-toolbar-btn" onClick={() => insertMarkdown("- ")} title="List">
|
||||||
className="notes-toolbar-btn"
|
<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
|
||||||
onClick={() => insertMarkdown("*", "*")}
|
|
||||||
title="Italic"
|
|
||||||
>
|
|
||||||
i
|
|
||||||
</button>
|
</button>
|
||||||
<button
|
<span style={{ marginLeft: "auto", fontSize: "0.65rem", color: "var(--weekly-text-muted, #999)", opacity: 0.6 }}>md</span>
|
||||||
className="notes-toolbar-btn"
|
|
||||||
onClick={() => insertMarkdown("[", "](url)")}
|
|
||||||
title="Link"
|
|
||||||
>
|
|
||||||
🔗
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="notes-toolbar-btn"
|
|
||||||
onClick={() => insertMarkdown("- ")}
|
|
||||||
title="List"
|
|
||||||
>
|
|
||||||
☑
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="notes-toolbar-btn"
|
|
||||||
onClick={() => insertMarkdown("")}
|
|
||||||
title="Image"
|
|
||||||
>
|
|
||||||
🖼️
|
|
||||||
</button>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
marginLeft: "auto",
|
|
||||||
fontSize: "0.75rem",
|
|
||||||
color: "#999",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Markdown supported
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<textarea
|
<textarea
|
||||||
ref={notesRef}
|
ref={notesRef}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user