My Studies: show studies as a grid or a list
Build and Push Docker Image / build-and-push (push) Failing after 19s
Build and Push Docker Image / build-and-push (push) Failing after 19s
A Grid / List toggle beside the sort and tag filters. List is one compact row per study (small book cover, title with Rename, passage, tags, date, Resume and Delete). The choice is remembered on the device. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a0971eab29
commit
dc825f0112
3 files changed
+57
-13
No files matched your search
+22
-6
@@ -51,6 +51,12 @@ export default function HomePage() {
|
||||
try { return localStorage.getItem('homeSort') || 'recent'; } catch { return 'recent'; }
|
||||
}); // 'recent' | 'title' | 'passage'
|
||||
const [homeTagFilter, setHomeTagFilter] = useState('');
|
||||
const [homeView, setHomeView] = useState(() => {
|
||||
try { return localStorage.getItem('homeView') === 'list' ? 'list' : 'grid'; } catch { return 'grid'; }
|
||||
}); // 'grid' | 'list'
|
||||
useEffect(() => {
|
||||
try { localStorage.setItem('homeView', homeView); } catch {}
|
||||
}, [homeView]);
|
||||
const [homeFullTextResults, setHomeFullTextResults] = useState(null); // null=idle, []=no match, [...]= results
|
||||
const fullTextTimerRef = useRef(null);
|
||||
const [renamingId, setRenamingId] = useState(null);
|
||||
@@ -163,6 +169,12 @@ export default function HomePage() {
|
||||
<option value="passage">Passage</option>
|
||||
</select>
|
||||
</label>
|
||||
<div role="group" aria-label="Studies layout" className="ml-auto flex overflow-hidden rounded-xl border border-[var(--r-line)] text-sm">
|
||||
{[['grid', 'Grid'], ['list', 'List']].map(([id, label]) => (
|
||||
<button key={id} type="button" aria-pressed={homeView === id} onClick={() => setHomeView(id)}
|
||||
className={`px-3 py-1.5 ${homeView === id ? 'bg-[var(--r-text)] text-[var(--r-bg)]' : 'text-[var(--r-sub)] hover:bg-black/5'}`}>{label}</button>
|
||||
))}
|
||||
</div>
|
||||
{allTags.length > 0 && (
|
||||
<label className="text-sm text-[var(--r-sub)]">Tag{' '}
|
||||
<select value={homeTagFilter} onChange={(e) => setHomeTagFilter(e.target.value)} className={`${fieldCls} ml-1`}>
|
||||
@@ -199,11 +211,15 @@ export default function HomePage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
<div className={homeView === 'list' ? 'flex flex-col gap-2' : 'grid gap-3 sm:grid-cols-2'}>
|
||||
{visible.map((entry) => (
|
||||
<div key={entry.id} className="flex flex-col gap-3 rounded-2xl border border-[var(--r-line)] bg-[var(--r-bar)] p-5">
|
||||
<BookCover summary={entry.chapterSummary} className="h-24" />
|
||||
<div className="flex-1">
|
||||
<div key={entry.id} className={homeView === 'list'
|
||||
? 'flex flex-col gap-3 rounded-2xl border border-[var(--r-line)] bg-[var(--r-bar)] p-3 sm:flex-row sm:items-center sm:gap-4'
|
||||
: 'flex flex-col gap-3 rounded-2xl border border-[var(--r-line)] bg-[var(--r-bar)] p-5'}>
|
||||
{homeView === 'list'
|
||||
? <BookCover summary={entry.chapterSummary} compact className="h-14 w-full sm:w-28 sm:shrink-0" />
|
||||
: <BookCover summary={entry.chapterSummary} className="h-24" />}
|
||||
<div className="min-w-0 flex-1">
|
||||
{renamingId === entry.id ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<input type="text" autoFocus value={renameValue} onChange={(e) => setRenameValue(e.target.value)}
|
||||
@@ -216,7 +232,7 @@ export default function HomePage() {
|
||||
<button type="button" onClick={() => setRenamingId(null)} className="text-sm text-[var(--r-sub)]">×</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className={`flex items-start gap-2 ${homeView === 'list' ? 'flex-wrap items-baseline' : 'justify-between'}`}>
|
||||
<h2 className="text-base font-medium">{entry.title}</h2>
|
||||
<button type="button" onClick={() => { setRenamingId(entry.id); setRenameValue(entry.title ?? ''); }} className="shrink-0 text-xs text-[var(--r-sub)] hover:text-[var(--r-text)]" title="Rename project">✎ Rename</button>
|
||||
</div>
|
||||
@@ -231,7 +247,7 @@ export default function HomePage() {
|
||||
)}
|
||||
<p className="mt-1 text-xs text-[var(--r-sub)]">{formatRelativeDate(entry.lastEdited)}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={`flex items-center gap-2 ${homeView === 'list' ? 'sm:w-56 sm:shrink-0' : ''}`}>
|
||||
<button type="button" onClick={() => resumeProject(entry.id)} className="flex-1 rounded-xl bg-[var(--r-text)] px-4 py-2 text-sm font-medium text-[var(--r-bg)] hover:opacity-90">Resume</button>
|
||||
<button type="button" onClick={() => deleteProject(entry.id)} className="rounded-xl border border-[var(--r-line)] px-4 py-2 text-sm text-[var(--r-danger,#b42318)] hover:bg-black/5">Delete</button>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user