personal memory agent
0
fork

Configure Feed

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

feat(ui): standardize workspace container styles across all apps

Introduces two standard workspace containers to eliminate ~150 lines of duplicate CSS and ensure consistent spacing across all apps:

- .workspace-content: centered, 1200px max-width for readable content (forms, lists, messages)
- .workspace-content-wide: full-width for data-heavy content (tables, grids, calendars)

Both include consistent 1.5rem/2rem padding with mobile responsiveness.

Updated all 10 apps:
- Standard container: home, settings, chat, todos, inbox, entities
- Wide container: search, calendar (month + day), import

Added workspace container guidance to APPS.md with examples and best practices.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

+71 -52
+39 -9
APPS.md
··· 303 303 304 304 ## CSS Styling 305 305 306 + ### Workspace Containers 307 + 308 + **Always wrap your workspace content** in one of these standardized containers for consistent spacing and layout: 309 + 310 + **For readable content** (forms, lists, messages, text): 311 + ```html 312 + <div class="workspace-content"> 313 + <!-- Your app content here --> 314 + </div> 315 + ``` 316 + 317 + **For data-heavy content** (tables, grids, calendars): 318 + ```html 319 + <div class="workspace-content-wide"> 320 + <!-- Your app content here --> 321 + </div> 322 + ``` 323 + 324 + **Key differences:** 325 + - `.workspace-content` - Centered with 1200px max-width, ideal for readability 326 + - `.workspace-content-wide` - Full viewport width, ideal for data tables and grids 327 + - Both include consistent padding and mobile responsiveness 328 + 329 + **See:** `convey/static/app.css` for implementation details 330 + 331 + **Examples:** 332 + - Standard: `apps/home/workspace.html`, `apps/todos/workspace.html`, `apps/inbox/workspace.html` 333 + - Wide: `apps/search/workspace.html`, `apps/calendar/_month.html`, `apps/import/workspace.html` 334 + 306 335 ### CSS Variables 307 336 308 337 Dynamic variables based on selected facet (update automatically on facet change): ··· 377 406 ## Best Practices 378 407 379 408 1. **Use underscores** in directory names (`my_app`, not `my-app`) 380 - 2. **Scope CSS** with unique class names to avoid conflicts 381 - 3. **Validate input** on all POST endpoints (use `error_response`) 382 - 4. **Check facet selection** when loading facet-specific data 383 - 5. **Use state.journal_root** for journal path (always available) 384 - 6. **Provide hooks** if app has facet counts 385 - 7. **Handle errors gracefully** with flash messages or JSON errors 386 - 8. **Test facet switching** to ensure content updates correctly 387 - 9. **Use background services** for WebSocket event handling 388 - 10. **Follow Flask patterns** for blueprints, url_for, etc. 409 + 2. **Wrap workspace content** in `.workspace-content` or `.workspace-content-wide` 410 + 3. **Scope CSS** with unique class names to avoid conflicts 411 + 4. **Validate input** on all POST endpoints (use `error_response`) 412 + 5. **Check facet selection** when loading facet-specific data 413 + 6. **Use state.journal_root** for journal path (always available) 414 + 7. **Provide hooks** if app has facet counts 415 + 8. **Handle errors gracefully** with flash messages or JSON errors 416 + 9. **Test facet switching** to ensure content updates correctly 417 + 10. **Use background services** for WebSocket event handling 418 + 11. **Follow Flask patterns** for blueprints, url_for, etc. 389 419 390 420 --- 391 421
+1 -1
apps/calendar/_day.html
··· 10 10 .occ-desc { margin-top:0.5em; white-space:pre-wrap; } 11 11 </style> 12 12 13 - <div class="calendar-content"> 13 + <div class="workspace-content-wide"> 14 14 {{ macros.day_heading(title, 15 15 prev_day and url_for('app:calendar.calendar_day', day=prev_day), 16 16 next_day and url_for('app:calendar.calendar_day', day=next_day),
+1 -2
apps/calendar/_month.html
··· 1 1 {# Calendar month overview - integrated with app facet system #} 2 2 3 3 <style> 4 - .calendar-content { padding: 0 1em; } 5 4 h1 { margin-bottom: 0.5em; } 6 5 7 6 #controls { display: flex; align-items: center; margin-bottom: 1em; gap: 6px; } ··· 34 33 } 35 34 </style> 36 35 37 - <div class="calendar-content"> 36 + <div class="workspace-content-wide"> 38 37 <div id="controls"> 39 38 <button id="prevMonth">&#8592;</button> 40 39 <span id="monthLabel"></span>
+3 -2
apps/chat/workspace.html
··· 3 3 display: flex; 4 4 flex-direction: column; 5 5 overflow-y: auto; 6 - padding: 1em; 7 6 } 8 7 .message {margin-bottom:0.75em; padding:0.75em 1em; border-radius:12px; max-width:75%; box-shadow:0 1px 3px rgba(0,0,0,0.1); animation:fadeInUp 0.3s ease-out; position:relative;} 9 8 .from-user {background:linear-gradient(135deg, #667eea 0%, #764ba2 100%); color:white; align-self:flex-end; margin-left:20%;} ··· 57 56 .activity-indicator span:nth-child(2) {animation-delay:-0.16s;} 58 57 </style> 59 58 60 - <div id="messages"></div> 59 + <div class="workspace-content"> 60 + <div id="messages"></div> 61 + </div> 61 62 62 63 <script src="{{ vendor_lib('marked') }}"></script> 63 64 <script>
+1 -7
apps/entities/workspace.html
··· 568 568 cursor: not-allowed; 569 569 } 570 570 571 - .entities-page { 572 - max-width: 1200px; 573 - margin: 0 auto; 574 - padding: 2em; 575 - } 576 - 577 571 .entities-loading { 578 572 text-align: center; 579 573 padding: 4em; ··· 596 590 } 597 591 </style> 598 592 599 - <div class="entities-page"> 593 + <div class="workspace-content"> 600 594 <div id="entities-loading" class="entities-loading"> 601 595 <div class="spinner"></div> 602 596 <p>Loading entities...</p>
+1 -6
apps/home/workspace.html
··· 1 - <div class="content"> 1 + <div class="workspace-content"> 2 2 <h1>Home Dashboard</h1> 3 3 <p>Welcome to Sunstone! This is the new app-based navigation system.</p> 4 4 ··· 8 8 </div> 9 9 10 10 <style> 11 - .content { 12 - max-width: 1400px; 13 - margin: 0 auto; 14 - padding: 2em; 15 - } 16 11 17 12 h1 { 18 13 font-size: 2.5em;
+1 -2
apps/import/workspace.html
··· 1 1 <style> 2 - .import-workspace { padding: 1em; } 3 2 .import-inputs { display: flex; gap: 1em; margin-bottom: 1em; } 4 3 .import-section { flex: 1; display: flex; flex-direction: column; } 5 4 #dropArea { border:2px dashed #999; padding:2em; text-align:center; cursor:pointer; flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 200px; } ··· 43 42 @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } 44 43 @keyframes spin { to { transform:rotate(360deg); } } 45 44 </style> 46 - <div class="import-workspace"> 45 + <div class="workspace-content-wide"> 47 46 <form id="importForm"> 48 47 <div class="import-inputs"> 49 48 <div class="import-section">
+1 -11
apps/inbox/workspace.html
··· 1 1 <style> 2 - .inbox-container { 3 - max-width: 1200px; 4 - margin: 0 auto; 5 - padding: 1.5em 2em 3em; 6 - } 7 - 8 2 .inbox-top { 9 3 display: flex; 10 4 flex-wrap: wrap; ··· 408 402 } 409 403 410 404 @media (max-width: 720px) { 411 - .inbox-container { 412 - padding: 1em 1em 2em; 413 - } 414 - 415 405 .inbox-top { 416 406 flex-direction: column; 417 407 align-items: stretch; ··· 419 409 } 420 410 </style> 421 411 422 - <div class="container inbox-container"> 412 + <div class="workspace-content"> 423 413 <div class="inbox-top"> 424 414 <div class="tabs"> 425 415 <div class="tab active" data-status="active">
+1 -2
apps/search/workspace.html
··· 1 1 <style> 2 - .search-content { padding: 0 1em; } 3 2 #resultsTable { width:100%; border-collapse:collapse; margin-top:1em; } 4 3 #resultsTable th, #resultsTable td { padding:8px; border-bottom:1px solid #ddd; } 5 4 #resultsTable td.date-cell { white-space:nowrap; cursor:pointer; } ··· 9 8 .load-more { margin-top:1em; padding:6px 12px; background:#007bff; color:white; border:none; border-radius:4px; cursor:pointer; } 10 9 </style> 11 10 12 - <div class="search-content"> 11 + <div class="workspace-content-wide"> 13 12 <form id="searchForm" class="input-area"> 14 13 <input id="query" type="text" placeholder="Search" /> 15 14 <button type="submit">Search</button>
+2 -3
apps/settings/workspace.html
··· 1 1 <style> 2 - .settings-content { padding:0 1em; } 3 2 button { padding:8px 16px; margin:0.5em 0; } 4 3 pre { background:#f5f5f5; padding:0.5em; } 5 4 ··· 103 102 .save-color-btn:active { transform: scale(0.98); } 104 103 </style> 105 104 106 - <div class="settings-content"> 107 - <div class="content" id="config"> 105 + <div class="workspace-content"> 106 + <div id="config"> 108 107 <!-- Identity Section (shown in all-facet mode) --> 109 108 <div class="config-section" id="identityConfig"> 110 109 <h2>Journal Configuration</h2>
+1 -7
apps/todos/workspace.html
··· 1 1 <style> 2 - .todo-container { 3 - max-width: 90vw; 4 - margin: 0 auto; 5 - padding: 1rem; 6 - } 7 - 8 2 .todo-header { 9 3 display: flex; 10 4 justify-content: space-between; ··· 300 294 } 301 295 </style> 302 296 303 - <div class="todo-container"> 297 + <div class="workspace-content"> 304 298 <div class="todo-header"> 305 299 <h1 class="todo-title">{{ title }}</h1> 306 300 <div class="todo-nav">
+19
convey/static/app.css
··· 43 43 margin-bottom: var(--app-bar-height); 44 44 } 45 45 46 + /* Standard workspace containers */ 47 + .workspace-content { 48 + max-width: 1200px; 49 + margin: 0 auto; 50 + padding: 1.5rem 2rem 2rem; 51 + } 52 + 53 + .workspace-content-wide { 54 + padding: 1.5rem 2rem 2rem; 55 + } 56 + 57 + /* Responsive */ 58 + @media (max-width: 768px) { 59 + .workspace-content, 60 + .workspace-content-wide { 61 + padding: 1rem; 62 + } 63 + } 64 + 46 65 /* Facet Bar (top) */ 47 66 .facet-bar { 48 67 position: fixed;