11local state = require (" codeme.profile.state" )
22local fmt = require (" codeme.profile.formatters" )
3- local helpers = require (" codeme.profile.helpers" )
43local ui = require (" codeme.ui" )
54
65local M = {}
76
87function M .render ()
9- local s = state .stats
8+ local s = state .stats or {}
109 local lines = {}
1110
12- -- Header with daily summary
13- local today_date = os.date (" %A, %B %d" )
14- local today_sessions = s .today .sessions or {}
15- local total_time = 0
16- for _ , session in ipairs (today_sessions ) do
17- total_time = total_time + (session .duration or 0 )
18- end
11+ local today = s .today or {}
12+ local total_time = today .total_time or 0
13+ local focus_score = s .focus_score or 0
14+ local peak_hour = today .peak_hour
15+ local languages = today .languages or {}
1916
20- local total_time = 0
21- for _ , session in ipairs (today_sessions ) do
22- total_time = total_time + (session .duration or 0 )
23- end
17+ -- Header
18+ local today_date = os.date (" %A, %B %d" )
2419
2520 table.insert (lines , {})
2621 table.insert (lines , {
@@ -32,23 +27,17 @@ function M.render()
3227 })
3328 table.insert (lines , {})
3429
35- if # today_sessions == 0 then
36- table.insert (lines , { { " No coding sessions yet today" , " commentfg" } })
30+ if total_time == 0 then
31+ table.insert (lines , { { " No coding activity yet today" , " commentfg" } })
3732 table.insert (lines , { { " Start working to track your productivity!" , " commentfg" } })
3833 table.insert (lines , {})
3934 return lines
4035 end
4136
42- -- 📖 Your Story Today (narrative summary )
37+ -- 📖 Your Story Today (aggregated, backend-safe )
4338 table.insert (lines , { { " 📖 Your Story Today" , " exgreen" } })
4439 table.insert (lines , {})
4540
46- local first_session = today_sessions [1 ]
47- local last_session = today_sessions [# today_sessions ]
48- local start_hour = tonumber (first_session .start :sub (12 , 13 ))
49- local end_hour = tonumber (last_session [" end" ]:sub (12 , 13 ))
50- local focus_score = s .focus_score or 0
51-
5241 local function get_period (hour )
5342 if hour >= 5 and hour < 12 then
5443 return " morning" , " 🌅"
@@ -61,125 +50,57 @@ function M.render()
6150 end
6251 end
6352
64- local start_period , start_icon = get_period (start_hour )
65- local end_period , end_icon = get_period (end_hour )
66-
67- -- Generate a human story
68- local story_parts = {
69- { " You started coding in the " , " commentfg" },
70- { start_period , " normal" },
71- { " " .. start_icon , " normal" },
72- }
73-
74- if # today_sessions > 1 then
75- table.insert (story_parts , { " and had " , " commentfg" })
76- table.insert (story_parts , { tostring (# today_sessions ), " exgreen" })
77- table.insert (story_parts , { " coding sessions" , " commentfg" })
78- else
79- table.insert (story_parts , { " for one focused session" , " commentfg" })
80- end
53+ local story = { { " You spent " , " commentfg" }, { fmt .fmt_time (total_time ), " exgreen" } }
8154
82- if start_period ~= end_period then
83- table.insert (story_parts , { " , continuing into the " , " commentfg" })
84- table.insert (story_parts , { end_period , " normal" })
85- table.insert (story_parts , { " " .. end_icon , " normal" })
55+ if peak_hour ~= nil and peak_hour >= 0 then
56+ local period , icon = get_period (peak_hour )
57+ table.insert (story , { " coding mostly in the " , " commentfg" })
58+ table.insert (story , { period , " normal" })
59+ table.insert (story , { " " .. icon , " normal" })
8660 end
8761
88- table.insert (story_parts , { " ." , " commentfg" })
89-
90- table.insert (lines , story_parts )
62+ table.insert (story , { " ." , " commentfg" })
63+ table.insert (lines , story )
9164 table.insert (lines , {})
9265
93- -- Add focus insight on separate line
94- local focus_insight = { { " " , " commentfg" } }
66+ -- 🎯 Focus Insight
67+ local focus_line = { { " " , " commentfg" } }
9568 if focus_score >= 80 then
96- table.insert (focus_insight , { " Deep focus mode! 🎯" , " exgreen" })
69+ table.insert (focus_line , { " Deep focus mode! 🎯" , " exgreen" })
9770 elseif focus_score >= 60 then
98- table.insert (focus_insight , { " Good concentration." , " exgreen" })
71+ table.insert (focus_line , { " Good concentration." , " exgreen" })
9972 elseif focus_score >= 40 then
100- table.insert (focus_insight , { " Some interruptions." , " exyellow" })
73+ table.insert (focus_line , { " Some interruptions." , " exyellow" })
10174 else
102- table.insert (focus_insight , { " Lots of context switching." , " exred" })
75+ table.insert (focus_line , { " Lots of context switching." , " exred" })
10376 end
104-
105- table.insert (lines , focus_insight )
106- table.insert (lines , {})
107-
108- -- ⏰ Session Timeline (compact with breaks)
109- table.insert (lines , { { " ⏰ Session Timeline" , " exgreen" } })
77+ table.insert (lines , focus_line )
11078 table.insert (lines , {})
11179
112- local longest_duration = 0
113- local longest_index = 1
114- for i , session in ipairs (today_sessions ) do
115- local duration = session .duration or 0
116- if duration > longest_duration then
117- longest_duration = duration
118- longest_index = i
119- end
120- end
121-
122- local tbl = { { " Time" , " Duration" , " Project" , " Languages" } }
123-
124- for i , session in ipairs (today_sessions ) do
125- local is_peak = (i == longest_index and # today_sessions > 1 )
126-
127- -- Get project
128- local project = session .project or " General"
129-
130- -- Get ALL languages (not just first)
131- local langs = " "
132- local languages_count = helpers .safe_length (session .languages )
133- if session .languages and languages_count > 0 then
134- local languages_table = helpers .safe_array_to_table (session .languages )
135- langs = helpers .format_list (session .languages )
136- if project == " General" and # languages_table > 0 then
137- project = languages_table [1 ]
138- end
139- end
80+ -- ⏰ Time by Language (replaces session timeline)
81+ if # languages > 0 then
82+ table.insert (lines , { { " ⏰ Time by Language" , " exgreen" } })
83+ table.insert (lines , {})
14084
141- -- Format time
142- local time_str = session .start :sub (12 , 16 )
143- local duration_str = fmt .fmt_time (session .duration or 0 )
144- if is_peak then
145- duration_str = duration_str .. " ⭐"
85+ local tbl = { { " Language" , " Time" } }
86+ for _ , lang in ipairs (languages ) do
87+ table.insert (tbl , {
88+ lang .name ,
89+ fmt .fmt_time (lang .value ),
90+ })
14691 end
14792
148- tbl [# tbl + 1 ] = {
149- time_str ,
150- duration_str ,
151- project ,
152- langs ~= " " and langs or " -" ,
153- }
154-
155- -- Show breaks between sessions (from original!)
156- if i < # today_sessions then
157- if session .break_after and session .break_after > 300 then
158- local break_icon = session .break_after < 1800 and " ☕" or " 🍽️"
159- tbl [# tbl + 1 ] = {
160- " " ,
161- break_icon .. " " .. fmt .fmt_time (session .break_after ),
162- " -" ,
163- " " ,
164- }
165- end
93+ for _ , l in ipairs (ui .table (tbl , state .width - 8 )) do
94+ table.insert (lines , l )
16695 end
96+ table.insert (lines , {})
16797 end
16898
169- for _ , l in ipairs (ui .table (tbl , state .width - 8 )) do
170- table.insert (lines , l )
171- end
172- table.insert (lines , {})
173-
17499 -- 📊 Quick Stats
175- local avg_time = math.floor (total_time / # today_sessions )
176-
177100 table.insert (lines , {
178101 { " 📊 " , " exgreen" },
179102 { fmt .fmt_time (total_time ), " exgreen" },
180103 { " total • " , " commentfg" },
181- { fmt .fmt_time (avg_time ), " normal" },
182- { " avg • " , " commentfg" },
183104 { string.format (" Focus %d%%" , focus_score ), focus_score >= 70 and " exgreen" or " exyellow" },
184105 })
185106 table.insert (lines , {})
@@ -188,7 +109,6 @@ function M.render()
188109 local hourly_activity = s .hourly_activity or {}
189110 local total_hourly = 0
190111
191- -- Use pairs() like insight.lua does (not indexed 0-23)
192112 for _ , time in pairs (hourly_activity ) do
193113 total_hourly = total_hourly + (time or 0 )
194114 end
@@ -197,16 +117,6 @@ function M.render()
197117 table.insert (lines , { { " ⏰ Your Peak Hours" , " exgreen" } })
198118 table.insert (lines , {})
199119
200- -- Build hourly map from the data structure
201- local hourly_map = {}
202- for hour_key , time in pairs (hourly_activity ) do
203- local hour_num = tonumber (hour_key )
204- if hour_num then
205- hourly_map [hour_num ] = time
206- end
207- end
208-
209- -- 6 blocks (better granularity)
210120 local blocks = {
211121 { label = " Night 00-04" , start_h = 0 , end_h = 3 , icon = " 🌙" },
212122 { label = " Early 04-08" , start_h = 4 , end_h = 7 , icon = " 🌅" },
@@ -216,13 +126,12 @@ function M.render()
216126 { label = " Night 20-24" , start_h = 20 , end_h = 23 , icon = " 🌃" },
217127 }
218128
219- local max_pct = 0
220- local peak_block = nil
129+ local peak_block , max_pct = nil , 0
221130
222131 for _ , block in ipairs (blocks ) do
223132 local block_time = 0
224133 for h = block .start_h , block .end_h do
225- block_time = block_time + (hourly_map [ h ] or 0 )
134+ block_time = block_time + (hourly_activity [ tostring ( h ) ] or 0 )
226135 end
227136
228137 if block_time > 0 then
@@ -232,39 +141,47 @@ function M.render()
232141 peak_block = block .label
233142 end
234143
235- local bar_hl = pct >= 30 and " exgreen" or pct >= 15 and " exblue" or " commentfg"
144+ local hl = pct >= 30 and " exgreen" or pct >= 15 and " exblue" or " commentfg"
236145 local line = {
237146 { " " .. block .icon .. " " , " normal" },
238147 { block .label .. " " , " commentfg" },
239148 }
240- for _ , seg in ipairs (ui .progress (pct , 18 , bar_hl )) do
149+ for _ , seg in ipairs (ui .progress (pct , 18 , hl )) do
241150 table.insert (line , seg )
242151 end
243152 table.insert (line , { string.format (" %d%%" , pct ), " commentfg" })
244153 table.insert (lines , line )
245154 end
246155 end
247156
248- -- Add insight
249157 if peak_block then
250158 table.insert (lines , {})
251159 table.insert (lines , {
252160 { " 💡 You're most productive in the " , " commentfg" },
253- { peak_block :sub (8 ), " exgreen" }, -- Remove icon prefix
161+ { peak_block :sub (8 ), " exgreen" },
254162 })
255163 end
256164
257165 table.insert (lines , {})
258166 end
259167
260- -- 🎯 Productivity Insight (from backend)
168+ -- 🎯 Productivity Trend
261169 local productivity_trend = s .productivity_trend or " "
262170 if productivity_trend ~= " " then
171+ local trend_text
172+ if productivity_trend == " increasing" then
173+ trend_text = " 📈 Productivity Increasing"
174+ elseif productivity_trend == " decreasing" then
175+ trend_text = " 📉 Slowing Down"
176+ else
177+ trend_text = " ➡️ Stable Pace"
178+ end
179+
263180 table.insert (lines , { { " 🎯 Trend" , " exgreen" } })
264181 table.insert (lines , {})
265182 table.insert (lines , {
266183 { " " , " commentfg" },
267- { productivity_trend , " exgreen" },
184+ { trend_text , " exgreen" },
268185 })
269186 table.insert (lines , {})
270187 end
0 commit comments