personal memory agent
0
fork

Configure Feed

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

at main 245 lines 5.6 kB view raw
1<style> 2.reflection-shell { 3 max-width: 900px; 4 margin: 0 auto; 5 padding: 2rem 2rem 5rem; 6 color: #1f2937; 7} 8 9.reflection-header { 10 display: flex; 11 justify-content: space-between; 12 gap: 1rem; 13 align-items: flex-start; 14 margin-bottom: 1.5rem; 15} 16 17.reflection-kicker { 18 margin: 0 0 0.35rem; 19 font-size: 0.85rem; 20 font-weight: 600; 21 letter-spacing: 0.08em; 22 text-transform: uppercase; 23 color: #92400e; 24} 25 26.reflection-title { 27 margin: 0; 28 font-size: clamp(1.8rem, 4vw, 2.7rem); 29 line-height: 1.1; 30 color: #111827; 31} 32 33.reflection-subtitle { 34 margin: 0.35rem 0 0; 35 font-size: 1rem; 36 color: #6b7280; 37} 38 39.reflection-actions { 40 display: flex; 41 gap: 0.75rem; 42 flex-wrap: wrap; 43} 44 45.reflection-button, 46.reflection-link-button { 47 display: inline-flex; 48 align-items: center; 49 justify-content: center; 50 min-height: 42px; 51 padding: 0 1rem; 52 border-radius: 999px; 53 border: 1px solid #d6d3d1; 54 background: #fffdf8; 55 color: #1f2937; 56 font: inherit; 57 text-decoration: none; 58 cursor: pointer; 59 transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease; 60} 61 62.reflection-button:hover, 63.reflection-link-button:hover { 64 background: #fef3c7; 65 border-color: #f59e0b; 66} 67 68.reflection-body, 69.reflection-index { 70 background: #fff; 71 border: 1px solid #e7e5e4; 72 border-radius: 18px; 73 padding: 1.5rem; 74 box-shadow: 0 20px 40px rgba(15, 23, 42, 0.04); 75} 76 77.reflection-body h1, 78.reflection-body h2, 79.reflection-body h3 { 80 color: #111827; 81} 82 83.reflection-body p, 84.reflection-body li, 85.reflection-index p, 86.reflection-index li { 87 line-height: 1.7; 88} 89 90.reflection-body blockquote { 91 margin: 1.5rem 0; 92 padding-left: 1rem; 93 border-left: 3px solid #f59e0b; 94 color: #6b7280; 95} 96 97.reflection-body a, 98.reflection-index a { 99 color: #b45309; 100} 101 102.reflection-body a:hover, 103.reflection-index a:hover { 104 color: #92400e; 105} 106 107.reflection-index-list { 108 list-style: none; 109 margin: 1.25rem 0 0; 110 padding: 0; 111 display: grid; 112 gap: 0.75rem; 113} 114 115.reflection-index-link { 116 display: flex; 117 justify-content: space-between; 118 gap: 1rem; 119 align-items: center; 120 padding: 1rem 1.1rem; 121 border-radius: 14px; 122 background: #fffbeb; 123 border: 1px solid #fcd34d; 124 text-decoration: none; 125 color: #1f2937; 126} 127 128.reflection-index-link:hover { 129 background: #fef3c7; 130} 131 132.reflection-index-day { 133 font-weight: 600; 134} 135 136.reflection-index-token { 137 color: #78716c; 138 font-size: 0.9rem; 139} 140 141@media (max-width: 720px) { 142 .reflection-shell { 143 padding: 1.25rem 1rem 4rem; 144 } 145 146 .reflection-header { 147 flex-direction: column; 148 } 149 150 .reflection-actions { 151 width: 100%; 152 } 153} 154</style> 155 156<div class="reflection-shell"> 157 {% if view_mode == "index" %} 158 <header class="reflection-header"> 159 <div> 160 <p class="reflection-kicker">weekly reflection</p> 161 <h2 class="reflection-title">reflections</h2> 162 <p class="reflection-subtitle">Available weekly reflections, newest first.</p> 163 </div> 164 </header> 165 <section class="reflection-index"> 166 {% if weeks %} 167 <ul class="reflection-index-list"> 168 {% for week in weeks %} 169 <li> 170 <a class="reflection-index-link" href="{{ week.url }}"> 171 <span class="reflection-index-day">week of {{ week.label }}</span> 172 <span class="reflection-index-token">{{ week.day }}</span> 173 </a> 174 </li> 175 {% endfor %} 176 </ul> 177 {% else %} 178 <p>No weekly reflections yet.</p> 179 {% endif %} 180 </section> 181 {% else %} 182 <header class="reflection-header"> 183 <div> 184 <p class="reflection-kicker">weekly reflection</p> 185 <h2 class="reflection-title">{{ reflection_week_label }}</h2> 186 <p class="reflection-subtitle">week of {{ reflection_week_label }}</p> 187 </div> 188 <div class="reflection-actions"> 189 <button type="button" class="reflection-button" id="copyReflectionButton">copy</button> 190 <a class="reflection-link-button" href="{{ pdf_url }}">download PDF</a> 191 </div> 192 </header> 193 194 <section class="reflection-body" id="reflectionBody"></section> 195 {% endif %} 196</div> 197 198{% if view_mode == "detail" %} 199<script> 200(() => { 201 const markdownSource = {{ reflection_markdown|tojson|safe }}; 202 const reflectionBody = document.getElementById('reflectionBody'); 203 const copyButton = document.getElementById('copyReflectionButton'); 204 const rawUrl = {{ raw_url|tojson|safe }}; 205 206 function copyText(text) { 207 if (navigator.clipboard && navigator.clipboard.writeText) { 208 return navigator.clipboard.writeText(text); 209 } 210 211 const area = document.createElement('textarea'); 212 area.value = text; 213 area.style.position = 'fixed'; 214 area.style.opacity = '0'; 215 document.body.appendChild(area); 216 area.select(); 217 document.execCommand('copy'); 218 document.body.removeChild(area); 219 return Promise.resolve(); 220 } 221 222 if (reflectionBody) { 223 reflectionBody.innerHTML = window.AppServices.renderMarkdown(markdownSource); 224 } 225 226 if (copyButton) { 227 copyButton.addEventListener('click', async () => { 228 const originalLabel = copyButton.textContent; 229 try { 230 const response = await fetch(rawUrl, { credentials: 'same-origin' }); 231 if (!response.ok) throw new Error('copy failed'); 232 await copyText(await response.text()); 233 copyButton.textContent = 'copied'; 234 } catch (_error) { 235 copyButton.textContent = 'failed'; 236 } finally { 237 window.setTimeout(() => { 238 copyButton.textContent = originalLabel; 239 }, 2000); 240 } 241 }); 242 } 243})(); 244</script> 245{% endif %}