feat: AnyDay tab edit via double-click; remove pencil icons; fix active tab style

CSS:
- Active tab no longer shows accent underline; instead border-bottom matches
  the someday area bg (#f9f9f9 / #1a1a1b dark), creating a raised browser-tab
  look where the active tab visually merges with the content below
- margin-bottom: -1px to cover the tab bar border-bottom on active tab

JSX:
- Double-click on any tab now opens TabVisualsPopover (edit tab)
- Pencil icon and dissolve-X button removed from tab wrappers
- TabVisualsPopover extended with: rename input, dissolve button
  (dissolve removes the tab grouping; lists are kept)
- onRename and onDissolve props added to TabVisualsPopover

v1.107.3
This commit is contained in:
mARTin-B78 2026-05-11 10:49:43 +02:00
parent 85912beb4b
commit 6ccf61f09a
3 changed files with 54 additions and 27 deletions

View File

@ -1,6 +1,6 @@
{
"name": "my-weekly-todo-list",
"version": "1.107.2",
"version": "1.107.3",
"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

@ -1677,9 +1677,14 @@ h3 {
color: var(--weekly-text, #222);
font-weight: 700;
border-color: var(--weekly-border, #e5e7eb);
border-bottom-color: var(--weekly-accent, #6366f1);
border-bottom-color: #f9f9f9;
background: var(--weekly-bg, #fff);
box-shadow: 0 -1px 0 0 var(--weekly-bg, #fff);
box-shadow: none;
margin-bottom: -1px;
}
.weekly-container.dark-mode .someday-tab-btn-h.active {
border-bottom-color: #1a1a1b;
}
.someday-tab-btn-h.drag-over {

View File

@ -8069,16 +8069,14 @@ export default function WeeklyView() {
<button
className={`someday-tab-btn-h ${activeSomedayTab === tab ? "active" : ""} ${dragOverTab === tab ? "drag-over" : ""}`}
onClick={() => setSomedayTab(tab)}
onDoubleClick={() => {
setEditingTabName(tab);
setRenamingTabValue(tab);
}}
onDoubleClick={(e) => { e.stopPropagation(); setEditingTabVisualsName(editingTabVisualsName === tab ? null : tab); }}
style={tv.color ? {
background: activeSomedayTab === tab ? tv.color : `${tv.color}22`,
color: activeSomedayTab === tab ? "#fff" : tv.color,
borderColor: tv.color,
borderBottomColor: activeSomedayTab === tab ? "transparent" : tv.color,
} : undefined}
title={t.renameTab}
title={profile.language === "de" ? "Doppelklick zum Bearbeiten" : "Double-click to edit"}
>
{tv.icon && (
<span style={{ display: "inline-flex", alignItems: "center", marginRight: "4px" }}>
@ -8089,16 +8087,6 @@ export default function WeeklyView() {
</button>
);
})()}
<button
onClick={(e) => { e.stopPropagation(); setEditingTabVisualsName(editingTabVisualsName === tab ? null : tab); }}
title={profile.language === "de" ? "Tab-Stil bearbeiten" : "Edit tab style"}
style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: "#bbb", display: "inline-flex", alignItems: "center" }}
><Pencil size={10} /></button>
<button
className="someday-tab-dissolve-h"
onClick={(e) => { e.stopPropagation(); dissolveTab(tab); }}
title={t.dissolveTab}
><X size={10} /></button>
{editingTabVisualsName === tab && (
<TabVisualsPopover
tabName={tab}
@ -8106,6 +8094,8 @@ export default function WeeklyView() {
darkMode={darkMode}
language={profile.language}
onChange={(updates) => updateTabVisuals(tab, updates)}
onRename={(newName) => { renameTab(tab, newName); setEditingTabVisualsName(null); }}
onDissolve={() => dissolveTab(tab)}
onClose={() => setEditingTabVisualsName(null)}
/>
)}
@ -10999,6 +10989,8 @@ function TabVisualsPopover({
darkMode,
language,
onChange,
onRename,
onDissolve,
onClose,
}: {
tabName: string;
@ -11006,9 +10998,12 @@ function TabVisualsPopover({
darkMode: boolean;
language: string;
onChange: (updates: { color?: string | null; icon?: string | null }) => void;
onRename: (newName: string) => void;
onDissolve: () => void;
onClose: () => void;
}) {
const [iconPickerOpen, setIconPickerOpen] = useState(false);
const [renameValue, setRenameValue] = useState(tabName);
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const onDoc = (e: MouseEvent) => {
@ -11018,36 +11013,50 @@ function TabVisualsPopover({
return () => document.removeEventListener("mousedown", onDoc);
}, [onClose]);
const de = language === "de";
const labelStyle = { fontSize: "0.75rem", color: darkMode ? "#9ca3af" : "#666", flex: 1 } as const;
return (
<div
ref={containerRef}
style={{
position: "absolute",
top: "calc(100% + 4px)",
top: "calc(100% + 6px)",
left: 0,
zIndex: 100,
background: darkMode ? "#1e1e2e" : "#fff",
border: `1px solid ${darkMode ? "#444" : "#e5e7eb"}`,
borderRadius: "10px",
padding: "10px",
padding: "12px",
boxShadow: "0 8px 24px rgba(0,0,0,0.18)",
minWidth: "220px",
minWidth: "230px",
display: "flex",
flexDirection: "column",
gap: "8px",
gap: "10px",
}}
onClick={(e) => e.stopPropagation()}
>
{/* Header */}
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<span style={{ fontSize: "0.78rem", fontWeight: 600, color: darkMode ? "#d1d5db" : "#444" }}>
{de ? `Tab-Stil: ${tabName}` : `Tab style: ${tabName}`}
<span style={{ fontSize: "0.78rem", fontWeight: 700, color: darkMode ? "#d1d5db" : "#333" }}>
{de ? "Tab bearbeiten" : "Edit tab"}
</span>
<button onClick={onClose} style={{ background: "none", border: "none", cursor: "pointer", color: darkMode ? "#9ca3af" : "#888", padding: "2px" }}>
<X size={14} />
</button>
</div>
{/* Rename */}
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<span style={{ fontSize: "0.75rem", color: darkMode ? "#9ca3af" : "#666", flex: 1 }}>{de ? "Icon" : "Icon"}</span>
<span style={labelStyle}>{de ? "Name" : "Name"}</span>
<input
value={renameValue}
onChange={(e) => setRenameValue(e.target.value)}
onBlur={() => { if (renameValue.trim() && renameValue.trim() !== tabName) onRename(renameValue.trim()); }}
onKeyDown={(e) => { if (e.key === "Enter") { if (renameValue.trim() && renameValue.trim() !== tabName) onRename(renameValue.trim()); (e.target as HTMLInputElement).blur(); } }}
style={{ flex: 1, fontSize: "0.8rem", border: `1px solid ${darkMode ? "#444" : "#e5e7eb"}`, borderRadius: "6px", padding: "4px 8px", background: darkMode ? "#2a2a3a" : "#f9f9f9", color: darkMode ? "#e5e7eb" : "#222", outline: "none" }}
/>
</div>
{/* Icon */}
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<span style={labelStyle}>{de ? "Icon" : "Icon"}</span>
<button
onClick={() => setIconPickerOpen((v) => !v)}
style={{ width: "32px", height: "32px", borderRadius: "8px", border: `1px solid ${darkMode ? "#444" : "#e5e7eb"}`, background: darkMode ? "#2a2a3a" : "#fff", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}
@ -11061,7 +11070,7 @@ function TabVisualsPopover({
)}
</div>
{iconPickerOpen && (
<div style={{ position: "absolute", top: "70px", left: "10px", zIndex: 110 }}>
<div style={{ position: "absolute", top: "110px", left: "10px", zIndex: 110 }}>
<IconPicker
selectedIcon={visuals.icon || ""}
onSelect={(name) => { onChange({ icon: name }); setIconPickerOpen(false); }}
@ -11069,8 +11078,9 @@ function TabVisualsPopover({
/>
</div>
)}
{/* Color */}
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
<span style={{ fontSize: "0.75rem", color: darkMode ? "#9ca3af" : "#666", flex: 1 }}>{de ? "Farbe" : "Color"}</span>
<span style={labelStyle}>{de ? "Farbe" : "Color"}</span>
<input
type="color"
value={visuals.color || "#6366f1"}
@ -11083,6 +11093,18 @@ function TabVisualsPopover({
</button>
)}
</div>
{/* Dissolve / delete */}
<div style={{ borderTop: `1px solid ${darkMode ? "#374151" : "#e5e7eb"}`, paddingTop: "8px" }}>
<button
onClick={() => { onDissolve(); onClose(); }}
style={{ width: "100%", display: "flex", alignItems: "center", gap: "8px", padding: "6px 8px", fontSize: "0.8rem", color: "#ef4444", background: "none", border: "none", cursor: "pointer", borderRadius: "6px", textAlign: "left" }}
onMouseEnter={(e) => (e.currentTarget.style.background = "rgba(239,68,68,0.08)")}
onMouseLeave={(e) => (e.currentTarget.style.background = "none")}
>
<Trash2 size={13} />
{de ? "Tab auflösen (Listen bleiben)" : "Dissolve tab (lists stay)"}
</button>
</div>
</div>
);
}