feat: move someday controls to horizontal tab bar, remove label column

Replace the someday-label-column with a unified horizontal tab bar
containing: collapse chevron, "any day" label, new list icon (ListPlus),
new tab icon (FolderPlus), divider, then tab buttons. All icons have
tooltips. Inline input for creating new tabs directly in the bar.

v1.27.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
mARTin 2026-03-11 08:53:30 +01:00
parent f05a7c9035
commit 8959aa7f5a
3 changed files with 157 additions and 190 deletions

View File

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

View File

@ -1509,6 +1509,33 @@ h3 {
display: none; display: none;
} }
.someday-bar-icon-btn {
background: none;
border: none;
cursor: pointer;
color: var(--weekly-text-light, #999);
padding: 3px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.15s, color 0.15s;
flex-shrink: 0;
}
.someday-bar-icon-btn:hover {
background: var(--weekly-hover-bg, rgba(0, 0, 0, 0.06));
color: var(--weekly-text, #333);
}
.someday-tabs-bar-divider {
width: 1px;
height: 16px;
background: var(--weekly-border, #e5e7eb);
flex-shrink: 0;
margin: 0 2px;
}
/* Someday Tab Buttons (horizontal) */ /* Someday Tab Buttons (horizontal) */
.someday-tab-btn-h { .someday-tab-btn-h {
background: none; background: none;

View File

@ -54,6 +54,8 @@ import {
PanelLeftOpen, PanelLeftOpen,
Type, Type,
FolderOpen, FolderOpen,
FolderPlus,
ListPlus,
Circle, Circle,
X, X,
Cable, Cable,
@ -256,6 +258,7 @@ const translations: Record<string, any> = {
confirmPassword: "Confirm Password", confirmPassword: "Confirm Password",
someday: "SOMEDAY", someday: "SOMEDAY",
lists: "Lists", lists: "Lists",
newList: "New list",
allTabs: "All", allTabs: "All",
newTab: "New tab", newTab: "New tab",
newTabName: "New tab name:", newTabName: "New tab name:",
@ -449,6 +452,7 @@ const translations: Record<string, any> = {
confirmPassword: "Passwort bestätigen", confirmPassword: "Passwort bestätigen",
someday: "IRGENDWANN", someday: "IRGENDWANN",
lists: "Listen", lists: "Listen",
newList: "Neue Liste",
allTabs: "Alle", allTabs: "Alle",
newTab: "Neuer Tab", newTab: "Neuer Tab",
newTabName: "Neuer Tab-Name:", newTabName: "Neuer Tab-Name:",
@ -641,6 +645,7 @@ const translations: Record<string, any> = {
confirmPassword: "Confirmer le mot de passe", confirmPassword: "Confirmer le mot de passe",
someday: "UN JOUR", someday: "UN JOUR",
lists: "Listes", lists: "Listes",
newList: "Nouvelle liste",
allTabs: "Tous", allTabs: "Tous",
newTab: "Nouvel onglet", newTab: "Nouvel onglet",
newTabName: "Nom du nouvel onglet :", newTabName: "Nom du nouvel onglet :",
@ -833,6 +838,7 @@ const translations: Record<string, any> = {
confirmPassword: "Confirmar contraseña", confirmPassword: "Confirmar contraseña",
someday: "ALGÚN DÍA", someday: "ALGÚN DÍA",
lists: "Listas", lists: "Listas",
newList: "Nueva lista",
allTabs: "Todas", allTabs: "Todas",
newTab: "Nueva pestaña", newTab: "Nueva pestaña",
newTabName: "Nombre de nueva pestaña:", newTabName: "Nombre de nueva pestaña:",
@ -1025,6 +1031,7 @@ const translations: Record<string, any> = {
confirmPassword: "Conferma password", confirmPassword: "Conferma password",
someday: "UN GIORNO", someday: "UN GIORNO",
lists: "Liste", lists: "Liste",
newList: "Nuova lista",
allTabs: "Tutte", allTabs: "Tutte",
newTab: "Nuova scheda", newTab: "Nuova scheda",
newTabName: "Nome nuova scheda:", newTabName: "Nome nuova scheda:",
@ -1461,6 +1468,8 @@ export default function WeeklyView() {
const [renamingTabValue, setRenamingTabValue] = useState(""); const [renamingTabValue, setRenamingTabValue] = useState("");
const [newTabForListId, setNewTabForListId] = useState<string | null>(null); const [newTabForListId, setNewTabForListId] = useState<string | null>(null);
const [newTabNameValue, setNewTabNameValue] = useState(""); const [newTabNameValue, setNewTabNameValue] = useState("");
const [creatingNewTab, setCreatingNewTab] = useState(false);
const [creatingNewTabName, setCreatingNewTabName] = useState("");
useEffect(() => { useEffect(() => {
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
@ -6362,152 +6371,82 @@ export default function WeeklyView() {
ref={somedaySectionRefCb} ref={somedaySectionRefCb}
className={`weekly-someday ${somedayExpanded ? "expanded" : "collapsed"} transition-colors duration-200`} className={`weekly-someday ${somedayExpanded ? "expanded" : "collapsed"} transition-colors duration-200`}
> >
<div style={{ display: "flex", flexDirection: "row", maxWidth: "100%", width: "100%" }}> {/* Someday tabs bar */}
{showTimeGrid && (
<div
className="someday-label-column"
style={{
width: "50px",
flexShrink: 0,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "flex-start",
borderRight: "1px solid var(--weekly-border)",
padding: "4px 4px",
gap: "4px",
position: "relative",
}}
>
<div
onClick={() => setSomedayExpanded(!somedayExpanded)}
style={{
cursor: "pointer",
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "0px",
}}
title={somedayExpanded ? "Collapse" : "Expand"}
>
<span
style={{
fontSize: "0.6rem",
fontWeight: 600,
color: "var(--weekly-text-light)",
textTransform: "uppercase",
letterSpacing: "0.05em",
lineHeight: 1.1,
textAlign: "center",
}}
>
any day
</span>
<span
style={{
fontSize: "0.55rem",
color: "#888",
marginTop: "1px",
}}
>
{somedayLists.length}{" "}
{translations[language]?.lists || translations["en"].lists}
</span>
</div>
<button
className="someday-add-btn dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:border-white transition-colors"
onClick={(e) => {
e.stopPropagation();
handleStartAddSomedayList();
}}
title="Add new list"
style={{
background: "none",
border: "1px dashed #ccc",
borderRadius: "50%",
width: "18px",
height: "18px",
display: "flex",
alignItems: "center",
justifyContent: "center",
cursor: "pointer",
color: "#888",
fontSize: "0.8rem",
lineHeight: 1,
padding: 0,
}}
>
+
</button>
</div>
)}
{!showTimeGrid && (
<div
className="someday-label-column"
style={{
display: "flex",
alignItems: "center",
padding: "4px 8px",
gap: "6px",
}}
>
<div
onClick={() => setSomedayExpanded(!somedayExpanded)}
style={{
cursor: "pointer",
display: "flex",
alignItems: "center",
gap: "6px",
}}
title={somedayExpanded ? "Collapse" : "Expand"}
>
<span
style={{
fontSize: "0.6rem",
fontWeight: 600,
color: "var(--weekly-text-light)",
textTransform: "uppercase",
letterSpacing: "0.05em",
}}
>
any day
</span>
<span style={{ fontSize: "0.55rem", color: "#888" }}>
{somedayLists.length}{" "}
{translations[language]?.lists || translations["en"].lists}
</span>
</div>
<button
className="someday-add-btn dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:border-white transition-colors"
onClick={(e) => {
e.stopPropagation();
handleStartAddSomedayList();
}}
title="Add new list"
style={{
background: "none",
border: "1px dashed #ccc",
borderRadius: "50%",
width: "18px",
height: "18px",
display: "flex",
alignItems: "center",
justifyContent: "center",
cursor: "pointer",
color: "#888",
fontSize: "0.8rem",
lineHeight: 1,
padding: 0,
}}
>
+
</button>
</div>
)}
<div ref={somedayGridRef} style={{ flex: 1, minWidth: 0, overflowX: "auto" }}>
{/* Horizontal tab bar above grid */}
{somedayExpanded && somedayTabs.length > 0 && (
<div className="someday-tabs-bar"> <div className="someday-tabs-bar">
<div
onClick={() => setSomedayExpanded(!somedayExpanded)}
style={{
cursor: "pointer",
display: "flex",
alignItems: "center",
gap: "4px",
marginRight: "4px",
}}
title={somedayExpanded ? "Collapse" : "Expand"}
>
<ChevronRight
size={14}
style={{
transform: somedayExpanded ? "rotate(90deg)" : "rotate(0deg)",
transition: "transform 0.15s",
color: "var(--weekly-text-light)",
flexShrink: 0,
}}
/>
<span style={{
fontSize: "0.7rem",
fontWeight: 600,
color: "var(--weekly-text-light)",
textTransform: "uppercase",
letterSpacing: "0.05em",
whiteSpace: "nowrap",
}}>
any day
</span>
</div>
<button
className="someday-bar-icon-btn"
onClick={() => handleStartAddSomedayList()}
title={t.newList}
>
<ListPlus size={14} />
</button>
<button
className="someday-bar-icon-btn"
onClick={() => { setCreatingNewTab(true); setCreatingNewTabName(""); }}
title={t.newTab}
>
<FolderPlus size={14} />
</button>
{creatingNewTab && (
<input
className="someday-tab-rename-input"
value={creatingNewTabName}
onChange={(e) => setCreatingNewTabName(e.target.value)}
onBlur={() => {
if (creatingNewTabName.trim()) {
setSomedayTab(creatingNewTabName.trim());
}
setCreatingNewTab(false);
}}
onKeyDown={(e) => {
if (e.key === "Enter") e.currentTarget.blur();
if (e.key === "Escape") setCreatingNewTab(false);
}}
placeholder={t.newTab}
autoFocus
style={{
fontSize: "0.75rem",
border: "1px solid var(--weekly-border)",
borderRadius: "3px",
padding: "2px 6px",
background: "var(--weekly-bg)",
color: "var(--weekly-text)",
width: "80px",
}}
/>
)}
<div className="someday-tabs-bar-divider" />
<button <button
className={`someday-tab-btn-h ${activeSomedayTab === null ? "active" : ""}`} className={`someday-tab-btn-h ${activeSomedayTab === null ? "active" : ""}`}
onClick={() => setSomedayTab(null)} onClick={() => setSomedayTab(null)}
@ -6558,7 +6497,8 @@ export default function WeeklyView() {
) )
))} ))}
</div> </div>
)} <div style={{ display: "flex", flexDirection: "row", maxWidth: "100%", width: "100%" }}>
<div ref={somedayGridRef} style={{ flex: 1, minWidth: 0, overflowX: "auto" }}>
{somedayExpanded && ( {somedayExpanded && (
<div <div
className={`weekly-someday-lists-grid cols-${Math.min(7, Math.max(1, viewDays))}`} className={`weekly-someday-lists-grid cols-${Math.min(7, Math.max(1, viewDays))}`}