fix: tab persistence and move tabs to horizontal bar above someday grid
Fix tabs vanishing on reload by adding missing `tab` field in fetchTasks() list mapping. Replace cramped vertical tabs in someday-label-column with a readable horizontal tab bar above the someday grid, working in both time-grid and non-time-grid modes. Double-click to rename, X to dissolve. v1.26.1 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1334656300
commit
b2a1981385
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.26.0",
|
||||
"version": "1.26.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": {
|
||||
|
||||
@ -1493,46 +1493,31 @@ h3 {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* Someday Tab Buttons (vertical in label column) */
|
||||
.someday-tab-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: var(--weekly-text-light, #999);
|
||||
font-size: 0.45rem;
|
||||
font-weight: 500;
|
||||
padding: 3px 4px;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1.2;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
/* Someday Tabs Bar (horizontal above grid) */
|
||||
.someday-tabs-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 4px 8px;
|
||||
border-bottom: 1px solid var(--weekly-border);
|
||||
overflow-x: auto;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.someday-tab-btn:hover {
|
||||
background: var(--weekly-hover-bg, rgba(0, 0, 0, 0.06));
|
||||
color: var(--weekly-text, #333);
|
||||
.someday-tabs-bar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.someday-tab-btn.active {
|
||||
background: var(--weekly-accent, #6366f1);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Someday Tab Buttons (horizontal in non-time-grid) */
|
||||
/* Someday Tab Buttons (horizontal) */
|
||||
.someday-tab-btn-h {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: var(--weekly-text-light, #999);
|
||||
font-size: 0.6rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
padding: 2px 8px;
|
||||
padding: 3px 10px;
|
||||
border-radius: 3px;
|
||||
white-space: nowrap;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
@ -1548,37 +1533,7 @@ h3 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Someday Tab Wrappers with dissolve buttons */
|
||||
.someday-tab-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.someday-tab-dissolve {
|
||||
position: absolute;
|
||||
right: -2px;
|
||||
top: -2px;
|
||||
background: var(--weekly-bg, #fff);
|
||||
border: 1px solid var(--weekly-border, #e5e7eb);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
color: var(--weekly-text-light, #999);
|
||||
padding: 1px;
|
||||
line-height: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
|
||||
.someday-tab-wrapper:hover .someday-tab-dissolve {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.someday-tab-dissolve:hover {
|
||||
color: #ef4444;
|
||||
border-color: #ef4444;
|
||||
}
|
||||
|
||||
/* Someday Tab Wrapper with dissolve button */
|
||||
.someday-tab-wrapper-h {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
@ -1620,33 +1575,6 @@ h3 {
|
||||
color: var(--weekly-text, #333);
|
||||
}
|
||||
|
||||
/* Mobile Someday Tabs Bar */
|
||||
.someday-tabs-mobile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.someday-tabs-mobile {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 6px 8px;
|
||||
overflow-x: auto;
|
||||
border-bottom: 1px solid var(--weekly-border);
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.someday-tabs-mobile::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hide the vertical tabs in label column on mobile */
|
||||
.someday-tabs {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Preferences Slide-in Panel */
|
||||
.preferences-panel {
|
||||
position: fixed;
|
||||
|
||||
@ -2706,6 +2706,7 @@ export default function WeeklyView() {
|
||||
fetchedLists = listData.lists.map((l: any) => ({
|
||||
id: l.id,
|
||||
title: l.title,
|
||||
tab: l.tab || null,
|
||||
tasks: [],
|
||||
externalId: l.externalId || null,
|
||||
externalProvider: l.externalProvider || null,
|
||||
@ -6438,80 +6439,6 @@ export default function WeeklyView() {
|
||||
>
|
||||
+
|
||||
</button>
|
||||
{/* Someday Tabs */}
|
||||
{somedayTabs.length > 0 && (
|
||||
<div className="someday-tabs" style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: "1px",
|
||||
width: "100%",
|
||||
marginTop: "4px",
|
||||
borderTop: "1px solid var(--weekly-border)",
|
||||
paddingTop: "4px",
|
||||
}}>
|
||||
<button
|
||||
className={`someday-tab-btn ${activeSomedayTab === null ? "active" : ""}`}
|
||||
onClick={() => setSomedayTab(null)}
|
||||
title={t.allTabs}
|
||||
>
|
||||
{t.allTabs}
|
||||
</button>
|
||||
{somedayTabs.map(tab => (
|
||||
editingTabName === tab ? (
|
||||
<input
|
||||
key={tab}
|
||||
className="someday-tab-rename-input"
|
||||
value={renamingTabValue}
|
||||
onChange={(e) => setRenamingTabValue(e.target.value)}
|
||||
onBlur={() => {
|
||||
renameTab(tab, renamingTabValue);
|
||||
setEditingTabName(null);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") e.currentTarget.blur();
|
||||
if (e.key === "Escape") setEditingTabName(null);
|
||||
}}
|
||||
autoFocus
|
||||
style={{
|
||||
width: "100%",
|
||||
fontSize: "0.5rem",
|
||||
textAlign: "center",
|
||||
border: "1px solid var(--weekly-border)",
|
||||
borderRadius: "3px",
|
||||
padding: "2px",
|
||||
background: "var(--weekly-bg)",
|
||||
color: "var(--weekly-text)",
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div key={tab} className="someday-tab-wrapper">
|
||||
<button
|
||||
className={`someday-tab-btn ${activeSomedayTab === tab ? "active" : ""}`}
|
||||
onClick={() => setSomedayTab(tab)}
|
||||
onDoubleClick={() => {
|
||||
setEditingTabName(tab);
|
||||
setRenamingTabValue(tab);
|
||||
}}
|
||||
title={t.renameTab}
|
||||
>
|
||||
{tab}
|
||||
</button>
|
||||
<button
|
||||
className="someday-tab-dissolve"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
dissolveTab(tab);
|
||||
}}
|
||||
title={t.dissolveTab}
|
||||
>
|
||||
<X size={8} />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{!showTimeGrid && (
|
||||
@ -6575,14 +6502,43 @@ export default function WeeklyView() {
|
||||
>
|
||||
+
|
||||
</button>
|
||||
{/* Horizontal tabs for non-time-grid */}
|
||||
{somedayTabs.length > 0 && (
|
||||
<>
|
||||
<button
|
||||
className={`someday-tab-btn-h ${activeSomedayTab === null ? "active" : ""}`}
|
||||
onClick={() => setSomedayTab(null)}
|
||||
>{t.allTabs}</button>
|
||||
{somedayTabs.map(tab => (
|
||||
</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">
|
||||
<button
|
||||
className={`someday-tab-btn-h ${activeSomedayTab === null ? "active" : ""}`}
|
||||
onClick={() => setSomedayTab(null)}
|
||||
>{t.allTabs}</button>
|
||||
{somedayTabs.map(tab => (
|
||||
editingTabName === tab ? (
|
||||
<input
|
||||
key={tab}
|
||||
className="someday-tab-rename-input"
|
||||
value={renamingTabValue}
|
||||
onChange={(e) => setRenamingTabValue(e.target.value)}
|
||||
onBlur={() => {
|
||||
renameTab(tab, renamingTabValue);
|
||||
setEditingTabName(null);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") e.currentTarget.blur();
|
||||
if (e.key === "Escape") setEditingTabName(null);
|
||||
}}
|
||||
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 key={tab} className="someday-tab-wrapper-h">
|
||||
<button
|
||||
className={`someday-tab-btn-h ${activeSomedayTab === tab ? "active" : ""}`}
|
||||
@ -6591,6 +6547,7 @@ export default function WeeklyView() {
|
||||
setEditingTabName(tab);
|
||||
setRenamingTabValue(tab);
|
||||
}}
|
||||
title={t.renameTab}
|
||||
>{tab}</button>
|
||||
<button
|
||||
className="someday-tab-dissolve-h"
|
||||
@ -6598,31 +6555,7 @@ export default function WeeklyView() {
|
||||
title={t.dissolveTab}
|
||||
><X size={10} /></button>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div ref={somedayGridRef} style={{ flex: 1, minWidth: 0, overflowX: "auto" }}>
|
||||
{/* Mobile tabs bar (visible only on small screens) */}
|
||||
{somedayExpanded && somedayTabs.length > 0 && (
|
||||
<div className="someday-tabs-mobile">
|
||||
<button
|
||||
className={`someday-tab-btn-h ${activeSomedayTab === null ? "active" : ""}`}
|
||||
onClick={() => setSomedayTab(null)}
|
||||
>{t.allTabs}</button>
|
||||
{somedayTabs.map(tab => (
|
||||
<div key={tab} className="someday-tab-wrapper-h">
|
||||
<button
|
||||
className={`someday-tab-btn-h ${activeSomedayTab === tab ? "active" : ""}`}
|
||||
onClick={() => setSomedayTab(tab)}
|
||||
>{tab}</button>
|
||||
<button
|
||||
className="someday-tab-dissolve-h"
|
||||
onClick={(e) => { e.stopPropagation(); dissolveTab(tab); }}
|
||||
title={t.dissolveTab}
|
||||
><X size={10} /></button>
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user