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:
mARTin 2026-03-17 10:47:55 +01:00
parent 85982f06a5
commit 2d386362ca
3 changed files with 128 additions and 99 deletions

View File

@ -1,6 +1,6 @@
{
"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",
"main": "index.js",
"scripts": {

View File

@ -772,24 +772,34 @@ h3 {
/* Inline Notes */
.weekly-notes-inline {
width: 100%;
margin-top: 0.5rem;
padding-left: 0;
padding-right: 0.5rem;
margin-top: 6px;
padding: 0;
animation: notesSlideIn 0.2s ease-out;
}
@keyframes notesSlideIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.weekly-notes-editor-inline {
width: 100%;
min-height: 80px;
padding: 0.5rem;
border: 1px solid #ddd; /* Light border for editor */
border-radius: 4px;
min-height: 60px;
max-height: 200px;
padding: 8px 10px;
border: 1px solid var(--weekly-border, #e5e7eb);
border-radius: 6px;
font-family: inherit;
font-size: 0.875rem;
font-size: 0.8rem;
line-height: 1.5;
color: var(--weekly-text);
background: #fdfdfd;
background: var(--weekly-bg, #fff);
resize: vertical;
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 */
@ -868,7 +878,10 @@ h3 {
.weekly-notes-editor-inline:focus {
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 */
@ -931,12 +944,14 @@ h3 {
.notes-toolbar {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.5rem;
padding: 0.25rem 0.5rem;
background: #f8f8f8;
border-radius: 4px;
border: 1px solid #eee;
gap: 2px;
margin-bottom: 4px;
padding: 3px 4px;
background: var(--weekly-settings-toggle-bg, #f3f4f6);
border-radius: 6px;
}
.dark-mode .notes-toolbar {
background: rgba(255, 255, 255, 0.06);
}
.notes-toolbar-btn {
@ -944,19 +959,23 @@ h3 {
border: none;
cursor: pointer;
color: var(--weekly-text-light);
font-size: 0.85rem;
padding: 2px 4px;
border-radius: 3px;
min-width: 20px;
font-size: 0.75rem;
padding: 3px 7px;
border-radius: 4px;
min-width: 24px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
transition: background 0.1s, color 0.1s;
}
.notes-toolbar-btn:hover {
background: rgba(0,0,0,0.05);
background: var(--weekly-bg, #fff);
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 */
@ -1051,21 +1070,37 @@ h3 {
}
/* Sub-tasks */
/* Subtask list — animated expand/collapse */
.subtask-list {
list-style: none;
padding: 0.125rem 0 0.125rem 1.25rem;
margin: 0;
padding: 4px 0 4px 12px;
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 {
display: flex;
align-items: center;
gap: 0.375rem;
padding: 0.125rem 0;
font-size: 0.8125rem;
gap: 6px;
padding: 3px 6px 3px 4px;
font-size: 0.8rem;
color: var(--weekly-text);
position: relative;
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 {
cursor: grabbing;
@ -1073,7 +1108,7 @@ h3 {
.subtask-item.completed .subtask-title {
text-decoration: line-through;
opacity: 0.5;
opacity: 0.4;
}
.subtask-checkbox {
@ -1085,12 +1120,12 @@ h3 {
display: flex;
align-items: center;
flex-shrink: 0;
transition: color 0.15s, transform 0.15s;
}
.subtask-checkbox:hover {
color: var(--weekly-teal);
transform: scale(1.15);
}
.subtask-item.completed .subtask-checkbox {
color: var(--weekly-teal);
}
@ -1102,8 +1137,8 @@ h3 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
transition: color 0.1s;
}
.subtask-title:hover {
color: var(--weekly-teal);
}
@ -1113,7 +1148,7 @@ h3 {
border: none;
background: transparent;
outline: none;
font-size: 0.8125rem;
font-size: 0.8rem;
font-family: inherit;
color: var(--weekly-text);
padding: 0;
@ -1122,25 +1157,28 @@ h3 {
.subtask-delete-btn {
background: none;
border: none;
padding: 0.125rem;
padding: 2px;
cursor: pointer;
color: var(--weekly-text-muted, #999);
opacity: 0;
transition: opacity 0.15s;
transition: opacity 0.15s, color 0.15s;
display: flex;
align-items: center;
border-radius: 3px;
}
.subtask-item:hover .subtask-delete-btn {
opacity: 1;
opacity: 0.6;
}
.subtask-delete-btn:hover {
color: #e53e3e;
color: #ef4444;
opacity: 1 !important;
background: rgba(239, 68, 68, 0.08);
}
.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 {
@ -1148,15 +1186,15 @@ h3 {
border: none;
background: transparent;
outline: none;
font-size: 0.8125rem;
font-size: 0.8rem;
font-family: inherit;
color: var(--weekly-text);
padding: 0.125rem 0;
padding: 2px 0;
}
.subtask-add-input::placeholder {
color: var(--weekly-text-muted, #999);
font-style: italic;
opacity: 0.7;
}
/* Task Input */

View File

@ -8943,6 +8943,7 @@ function TaskItem({
const total = task.subTasks!.length;
const allDone = completed === total;
const expanded = isSubTasksOpen || isSubTaskInputOpen;
const pct = total > 0 ? (completed / total) * 100 : 0;
return (
<button
onClick={(e) => {
@ -8954,25 +8955,46 @@ function TaskItem({
style={{
display: "inline-flex",
alignItems: "center",
gap: "3px",
padding: "2px 7px",
borderRadius: "10px",
background: expanded ? "rgba(99, 102, 241, 0.15)" : allDone ? "rgba(34, 197, 94, 0.15)" : "rgba(0,0,0,0.08)",
color: expanded ? "#6366f1" : allDone ? "#22c55e" : "#555",
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)",
gap: "4px",
padding: "2px 8px 2px 6px",
borderRadius: "12px",
background: "transparent",
color: allDone ? "var(--weekly-teal, #0d9488)" : "var(--weekly-text-light, #9ca3af)",
border: "none",
cursor: "pointer",
fontSize: "0.7rem",
fontWeight: 600,
lineHeight: 1,
flexShrink: 0,
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" />
</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>
);
})()}
@ -8989,14 +9011,15 @@ function TaskItem({
style={{
display: "inline-flex",
alignItems: "center",
padding: "2px 4px",
borderRadius: "3px",
background: isNotesOpen ? "rgba(245, 158, 11, 0.12)" : "rgba(0,0,0,0.05)",
color: isNotesOpen ? "#f59e0b" : "#888",
gap: "2px",
padding: "2px 5px",
borderRadius: "4px",
background: isNotesOpen ? "rgba(245, 158, 11, 0.1)" : "transparent",
color: isNotesOpen ? "#f59e0b" : "var(--weekly-text-muted, #999)",
border: "none",
cursor: "pointer",
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">
@ -9005,6 +9028,9 @@ function TaskItem({
<line x1="16" y1="13" x2="8" y2="13" />
<line x1="16" y1="17" x2="8" y2="17" />
</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>
)}
@ -9253,50 +9279,15 @@ function TaskItem({
onClick={(e) => e.stopPropagation()}
>
<div className="notes-toolbar">
<button
className="notes-toolbar-btn"
onClick={() => insertMarkdown("**", "**")}
title="Bold"
>
B
<button className="notes-toolbar-btn" onClick={() => insertMarkdown("**", "**")} title="Bold" style={{ fontWeight: 700 }}>B</button>
<button className="notes-toolbar-btn" onClick={() => insertMarkdown("*", "*")} title="Italic" style={{ fontStyle: "italic" }}>I</button>
<button className="notes-toolbar-btn" onClick={() => insertMarkdown("[", "](url)")} title="Link">
<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>
</button>
<button
className="notes-toolbar-btn"
onClick={() => insertMarkdown("*", "*")}
title="Italic"
>
i
<button className="notes-toolbar-btn" onClick={() => insertMarkdown("- ")} title="List">
<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>
</button>
<button
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("![alt text](", ")")}
title="Image"
>
🖼
</button>
<span
style={{
marginLeft: "auto",
fontSize: "0.75rem",
color: "#999",
}}
>
Markdown supported
</span>
<span style={{ marginLeft: "auto", fontSize: "0.65rem", color: "var(--weekly-text-muted, #999)", opacity: 0.6 }}>md</span>
</div>
<textarea
ref={notesRef}