feat(frontend): add calendar click to switch conversation by date
- Add selected date state and conversation mapping in useSidebarPlan - Connect calendar cells to conversation switching logic - Add conversation indicator dot on dates with sessions - Only clickable dates show hand cursor (today + dates with conversations) - Add .selected styling for non-today dates, today keeps blue - Fix hover effect to only apply to non-today dates - Add daily doc for session date mapping feature BREAKING: Calendar click now switches sessions by date
This commit is contained in:
@@ -50,6 +50,9 @@ const {
|
||||
systemTelemetry,
|
||||
sessionTelemetry,
|
||||
sendMessage,
|
||||
selectConversation,
|
||||
newConversation,
|
||||
loadConversations,
|
||||
formatTime,
|
||||
autoResize,
|
||||
handleFileSelect,
|
||||
@@ -74,8 +77,9 @@ const {
|
||||
calendarCells, calendarYear, calendarMonth, todayPlanCounters,
|
||||
sidebarWeekLabels, sidebarStatusHeadline, sidebarStatusBreakdown,
|
||||
sidebarFocusItems, sidebarReviewAchievements, sidebarReviewReflections,
|
||||
sidebarFeedItems, topbarFeedItems, sidebarCollapsedModules
|
||||
} = useSidebarPlan(clientTime, loadDailyDigest)
|
||||
sidebarFeedItems, topbarFeedItems, sidebarCollapsedModules,
|
||||
selectedDate, selectCalendarDate
|
||||
} = useSidebarPlan(clientTime, loadDailyDigest, store.conversations)
|
||||
|
||||
// --- Local UI state ---
|
||||
const sidebarCollapsed = ref(false)
|
||||
@@ -111,6 +115,33 @@ function closeKnowledgeHud() { knowledgeHudOpen.value = false }
|
||||
function handleSelectFolder(folder: any) { selectedFolder.value = folder }
|
||||
function handleOpenPreview(doc: any) { previewDoc.value = doc }
|
||||
|
||||
function handleCalendarDateSelect(dateKey: string) {
|
||||
selectCalendarDate(dateKey)
|
||||
|
||||
// Reload conversations to get latest data
|
||||
loadConversations().then(() => {
|
||||
// Find conversation that matches the selected date (by updated_at)
|
||||
const targetDate = new Date(dateKey)
|
||||
const targetDateStart = new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate())
|
||||
const targetDateEnd = new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate() + 1)
|
||||
|
||||
// Find conversation that falls on the selected date
|
||||
const conversation = store.conversations.find((conv) => {
|
||||
const convDate = new Date(conv.updated_at)
|
||||
return convDate >= targetDateStart && convDate < targetDateEnd
|
||||
})
|
||||
|
||||
if (conversation) {
|
||||
selectConversation(conversation.id)
|
||||
} else {
|
||||
// No conversation for this date, create a new one
|
||||
newConversation()
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error('[Calendar] Error loading conversations:', err)
|
||||
})
|
||||
}
|
||||
|
||||
// --- Message rendering utilities (kept inline for clarity) ---
|
||||
function formatUptime(seconds: number) {
|
||||
const days = Math.floor(seconds / 86400)
|
||||
@@ -269,9 +300,11 @@ function renderMarkdown(content: string) {
|
||||
v-for="cell in calendarCells"
|
||||
:key="cell.key"
|
||||
class="calendar-day"
|
||||
:class="{ active: cell.active, busy: cell.busy, muted: cell.value === null }"
|
||||
:class="{ active: cell.active, busy: cell.busy, muted: cell.value === null, selected: cell.selected, clickable: cell.hasConversation || cell.active }"
|
||||
@click="(cell.hasConversation || cell.active) && handleCalendarDateSelect(cell.key)"
|
||||
>
|
||||
{{ cell.value ?? '' }}
|
||||
<span v-if="cell.hasConversation" class="conv-indicator"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -355,24 +388,11 @@ function renderMarkdown(content: string) {
|
||||
<div class="chat-model-panel">
|
||||
<label class="chat-model-label" for="chat-model-select">
|
||||
<Sparkles :size="12" />
|
||||
<span>CHAT MODEL</span>
|
||||
<span>MODEL</span>
|
||||
</label>
|
||||
<select
|
||||
id="chat-model-select"
|
||||
v-model="selectedModelName"
|
||||
class="chat-model-select"
|
||||
:disabled="isSending || isLoadingModels || chatModels.length === 0"
|
||||
>
|
||||
<option v-if="chatModels.length === 0" value="">
|
||||
{{ isLoadingModels ? 'Loading models...' : 'No chat models' }}
|
||||
</option>
|
||||
<option v-for="model in chatModels" :key="model.name" :value="model.name">
|
||||
{{ model.name }}
|
||||
</option>
|
||||
</select>
|
||||
<div v-if="selectedModel" class="chat-model">
|
||||
<div class="chat-model-display">
|
||||
<Sparkles :size="12" />
|
||||
<span>{{ selectedModel.model }}</span>
|
||||
<span>{{ selectedModel?.model || selectedModelName || 'Default' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -578,21 +598,6 @@ function renderMarkdown(content: string) {
|
||||
<div class="section-label">// RUNTIME STATUS</div>
|
||||
<div class="runtime-meta-panel runtime-meta-panel-merged">
|
||||
<div class="runtime-panel-title">SYSTEM</div>
|
||||
<div class="runtime-meta-item">
|
||||
<span class="runtime-meta-key">DATE</span>
|
||||
<span class="runtime-meta-value">{{ formatClientDate(clientTime) }}</span>
|
||||
</div>
|
||||
<div class="runtime-meta-item">
|
||||
<span class="runtime-meta-key">TIME</span>
|
||||
<span class="runtime-meta-value">{{ formatClientClock(clientTime) }}</span>
|
||||
</div>
|
||||
<div class="runtime-meta-item">
|
||||
<span class="runtime-meta-key">WEATHER</span>
|
||||
<span class="runtime-meta-value weather-inline">
|
||||
<i :class="['wi', weatherIcon]"></i>
|
||||
<span>{{ weatherSummary }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="runtime-meta-item">
|
||||
<span class="runtime-meta-key">OS</span>
|
||||
<span class="runtime-meta-value">{{ systemMeta.systemName }}</span>
|
||||
|
||||
Reference in New Issue
Block a user