@@ -7,6 +7,7 @@ let allSessions = [];
77let filteredSessions = [ ] ;
88let currentView = 'sessions' ; // sessions, projects, timeline, activity, starred
99let grouped = true ;
10+ let layout = localStorage . getItem ( 'codedash-layout' ) || 'grid' ; // 'grid' or 'list'
1011let searchQuery = '' ;
1112let toolFilter = null ; // null, 'claude', 'codex'
1213let tagFilter = '' ;
@@ -325,6 +326,42 @@ function renderCard(s, idx) {
325326 return html ;
326327}
327328
329+ function toggleLayout ( ) {
330+ layout = layout === 'grid' ? 'list' : 'grid' ;
331+ localStorage . setItem ( 'codedash-layout' , layout ) ;
332+ var btn = document . getElementById ( 'layoutBtn' ) ;
333+ if ( btn ) btn . classList . toggle ( 'active' , layout === 'list' ) ;
334+ var icon = document . getElementById ( 'layoutIcon' ) ;
335+ if ( icon ) {
336+ icon . innerHTML = layout === 'list'
337+ ? '<line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/>'
338+ : '<rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/>' ;
339+ }
340+ render ( ) ;
341+ }
342+
343+ function renderListCard ( s , idx ) {
344+ var isStarred = stars . indexOf ( s . id ) >= 0 ;
345+ var isSelected = selectedIds . has ( s . id ) ;
346+ var isFocused = focusedIndex === idx ;
347+ var projName = getProjectName ( s . project ) ;
348+ var projColor = getProjectColor ( projName ) ;
349+
350+ var classes = 'list-row' ;
351+ if ( isSelected ) classes += ' selected' ;
352+ if ( isFocused ) classes += ' focused' ;
353+
354+ var html = '<div class="' + classes + '" data-id="' + s . id + '" onclick="onCardClick(\'' + s . id + '\', event)">' ;
355+ html += '<span class="tool-badge tool-' + s . tool + '">' + escHtml ( s . tool ) + '</span>' ;
356+ html += '<span class="list-project" style="color:' + projColor + '">' + escHtml ( projName ) + '</span>' ;
357+ html += '<span class="list-msg">' + escHtml ( ( s . first_message || '' ) . slice ( 0 , 80 ) ) + '</span>' ;
358+ html += '<span class="list-meta">' + s . messages + ' msgs</span>' ;
359+ html += '<span class="list-time">' + timeAgo ( s . last_ts ) + '</span>' ;
360+ html += '<button class="star-btn' + ( isStarred ? ' active' : '' ) + '" onclick="event.stopPropagation();toggleStar(\'' + s . id + '\')">★</button>' ;
361+ html += '</div>' ;
362+ return html ;
363+ }
364+
328365function onCardClick ( id , event ) {
329366 if ( selectMode ) {
330367 toggleSelect ( id , event ) ;
@@ -384,15 +421,18 @@ function render() {
384421 return ;
385422 }
386423
424+ var renderFn = layout === 'list' ? renderListCard : renderCard ;
387425 if ( grouped ) {
388- renderGrouped ( content , sessions ) ;
426+ renderGrouped ( content , sessions , renderFn ) ;
389427 } else {
390428 var idx2 = 0 ;
391- content . innerHTML = sessions . map ( function ( s ) { return renderCard ( s , idx2 ++ ) ; } ) . join ( '' ) ;
429+ var wrapClass = layout === 'list' ? 'list-view' : 'grid-view' ;
430+ content . innerHTML = '<div class="' + wrapClass + '">' + sessions . map ( function ( s ) { return renderFn ( s , idx2 ++ ) ; } ) . join ( '' ) + '</div>' ;
392431 }
393432}
394433
395- function renderGrouped ( container , sessions ) {
434+ function renderGrouped ( container , sessions , renderFn ) {
435+ renderFn = renderFn || renderCard ;
396436 var groups = { } ;
397437 sessions . forEach ( function ( s ) {
398438 var key = getProjectName ( s . project ) ;
@@ -415,9 +455,10 @@ function renderGrouped(container, sessions) {
415455 html += '<span class="group-count">' + groups [ key ] . length + '</span>' ;
416456 html += '<span class="group-chevron">▼</span>' ;
417457 html += '</div>' ;
418- html += '<div class="group-body">' ;
458+ var bodyClass = layout === 'list' ? 'group-body group-body-list' : 'group-body' ;
459+ html += '<div class="' + bodyClass + '">' ;
419460 groups [ key ] . forEach ( function ( s ) {
420- html += renderCard ( s , globalIdx ++ ) ;
461+ html += renderFn ( s , globalIdx ++ ) ;
421462 } ) ;
422463 html += '</div></div>' ;
423464 } ) ;
@@ -479,7 +520,7 @@ function renderProjects(container, sessions) {
479520 var totalSize = info . sessions . reduce ( function ( sum , s ) { return sum + ( s . file_size || 0 ) ; } , 0 ) ;
480521 var latest = info . sessions [ 0 ] ;
481522
482- html += '<div class="project-card" onclick="onSearch (\'' + escHtml ( name ) + '\');document.querySelector(\'.search-box\').value=\'' + escHtml ( name ) + '\'">' ;
523+ html += '<div class="project-card" onclick="openProject (\'' + escHtml ( name ) . replace ( / ' / g , "\\'" ) + '\') ">' ;
483524 html += '<div class="project-card-header">' ;
484525 html += '<span class="group-dot" style="background:' + color + '"></span>' ;
485526 html += '<span class="project-card-name">' + escHtml ( name ) + '</span>' ;
@@ -898,6 +939,18 @@ async function bulkDelete() {
898939 }
899940}
900941
942+ // ── Project actions ────────────────────────────────────────────
943+
944+ function openProject ( name ) {
945+ currentView = 'sessions' ;
946+ searchQuery = name ;
947+ document . querySelector ( '.search-box' ) . value = name ;
948+ document . querySelectorAll ( '.sidebar-item' ) . forEach ( function ( el ) {
949+ el . classList . toggle ( 'active' , el . getAttribute ( 'data-view' ) === 'sessions' ) ;
950+ } ) ;
951+ applyFilters ( ) ;
952+ }
953+
901954// ── Themes ─────────────────────────────────────────────────────
902955
903956function setTheme ( theme ) {
0 commit comments