personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #124 from kognova/codex/-title----make-tabs-linkable-and-update-readme

Add anchor links to day view and calendar events

authored by

Jer Miller and committed by
GitHub
6b294e7b e3a1b5f0

+47 -11
+8
dream/README.md
··· 45 45 46 46 This small structure keeps dependencies clear and makes it easy to focus on a single page. 47 47 48 + ## Links and navigation 49 + 50 + - `/calendar` shows the month view. Clicking a day opens `/calendar/YYYYMMDD`. 51 + - Individual markdown files for a day are displayed as tabs. Each tab can be 52 + linked directly via an anchor, e.g. `/calendar/20240101#meetings`. 53 + - Events in the calendar hour view modal also link to these anchors so you can 54 + jump straight from an event to the relevant markdown section. 55 +
+5 -1
dream/templates/calendar.html
··· 95 95 right:10px; 96 96 border-radius:4px; 97 97 opacity:0.9; 98 + display:block; 99 + text-decoration:none; 98 100 } 99 101 .occ.meeting{background:#007bff;} 100 102 .occ.message{background:#28a745;} ··· 259 261 const title = escapeHtml(o.title || o.summary || type); 260 262 const left = `calc(${col*colWidth}% + 10px)`; 261 263 const width = `calc(${colWidth}% - 20px)`; 262 - html += `<div class='occ ${type}' style='top:${top}%;height:${height}%;left:${left};width:${width};right:auto' title='${title}'></div>`; 264 + const slug = o.slug ? `#${o.slug}` : ''; 265 + const href = `${dayBase}${dateStr}${slug}`; 266 + html += `<a class='occ ${type}' href='${href}' style='top:${top}%;height:${height}%;left:${left};width:${width};right:auto' title='${title}'></a>`; 263 267 }); 264 268 265 269 html += "</div></div>";
+24 -8
dream/templates/day.html
··· 23 23 </h1> 24 24 <div class="tabs"> 25 25 {% for file in files %} 26 - <div class="tab{% if loop.first %} active{% endif %}" data-target="tab{{ loop.index0 }}">{{ file.label }}</div> 26 + <a class="tab{% if loop.first %} active{% endif %}" href="#{{ file.slug }}" data-target="{{ file.slug }}">{{ file.label }}</a> 27 27 {% endfor %} 28 28 </div> 29 29 {% for file in files %} 30 - <div class="content" id="tab{{ loop.index0 }}" style="{% if not loop.first %}display:none{% endif %}"> 30 + <div class="content" id="{{ file.slug }}" style="{% if not loop.first %}display:none{% endif %}"> 31 31 <div class="markdown">{{ file.html|safe }}</div> 32 32 </div> 33 33 {% endfor %} 34 34 </div> 35 35 <script> 36 - document.querySelectorAll('.tab').forEach(t=>t.onclick=()=>{ 37 - document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active')); 38 - document.querySelectorAll('.content').forEach(c=>c.style.display='none'); 39 - t.classList.add('active'); 40 - document.getElementById(t.dataset.target).style.display='block'; 41 - }); 36 + const tabs = document.querySelectorAll('.tab'); 37 + const contents = document.querySelectorAll('.content'); 38 + 39 + function showTab(id){ 40 + tabs.forEach(x=>x.classList.remove('active')); 41 + contents.forEach(c=>c.style.display='none'); 42 + const tab = document.querySelector(`.tab[data-target="${id}"]`); 43 + const content = document.getElementById(id); 44 + if(tab) tab.classList.add('active'); 45 + if(content) content.style.display='block'; 46 + if(history.replaceState){ 47 + history.replaceState(null, '', '#' + id); 48 + } else { 49 + location.hash = '#' + id; 50 + } 51 + } 52 + 53 + tabs.forEach(t=>t.addEventListener('click', e=>{e.preventDefault();showTab(t.dataset.target);})); 54 + const initial = location.hash.slice(1); 55 + if(initial && document.getElementById(initial)){ 56 + showTab(initial); 57 + } 42 58 </script> 43 59 {% endblock %}
+7
dream/utils.py
··· 184 184 "summary": occ.get("summary", ""), 185 185 "type": occ.get("type", ""), 186 186 } 187 + source = occ.get("source") 188 + if ( 189 + isinstance(source, str) 190 + and source.startswith("ponder_") 191 + and source.endswith(".md") 192 + ): 193 + o["slug"] = source[7:-3] 187 194 if occ.get("start"): 188 195 o["startTime"] = _combine(name, occ["start"]) 189 196 if occ.get("end"):
+3 -2
dream/views/calendar.py
··· 39 39 html = markdown.markdown(text) 40 40 except Exception: 41 41 html = "<p>Error loading file.</p>" 42 - label = name[7:-3].replace("_", " ").title() 43 - files.append({"label": label, "html": html}) 42 + base = name[7:-3] 43 + label = base.replace("_", " ").title() 44 + files.append({"label": label, "html": html, "slug": base}) 44 45 title = format_date(day) 45 46 days = sorted(d for d in os.listdir(state.journal_root) if re.fullmatch(DATE_RE, d)) 46 47 prev_day = next_day = None