| 1 | <html> |
| 2 | |
| 3 | <head> |
| 4 | <title>Memory Dashboard</title> |
| 5 | <script type="module"> |
| 6 | import { store } from "/plugins/_memory/webui/memory-dashboard-store.js"; |
| 7 | </script> |
| 8 | </head> |
| 9 | |
| 10 | <body> |
| 11 | <div x-data> |
| 12 | <template x-if="$store.memoryDashboardStore"> |
| 13 | <div x-create="$store.memoryDashboardStore.onOpen()" x-destroy="$store.memoryDashboardStore.cleanup()" |
| 14 | class="memory-dashboard"> |
| 15 | |
| 16 | <!-- Search and Filters Section --> |
| 17 | <div class="filters-header memory-filters-header"> |
| 18 | <div class="filter-group-inline filter-memory-dir"> |
| 19 | <label for="memory-subdir-select">Memory Directory</label> |
| 20 | <select id="memory-subdir-select" x-model="$store.memoryDashboardStore.selectedMemorySubdir" |
| 21 | @change="$store.memoryDashboardStore.onMemorySubdirChange()" |
| 22 | :disabled="$store.memoryDashboardStore.loadingSubdirs"> |
| 23 | <template x-for="subdir in $store.memoryDashboardStore.memorySubdirs" :key="subdir"> |
| 24 | <option :value="subdir" x-text="subdir" |
| 25 | :selected="subdir === $store.memoryDashboardStore.selectedMemorySubdir"> |
| 26 | </option> |
| 27 | </template> |
| 28 | </select> |
| 29 | </div> |
| 30 | |
| 31 | <div class="filter-group-inline filter-area"> |
| 32 | <label for="area-filter">Area</label> |
| 33 | <select id="area-filter" x-model="$store.memoryDashboardStore.areaFilter"> |
| 34 | <option value="">All Areas</option> |
| 35 | <option value="main">Main</option> |
| 36 | <option value="fragments">Fragments</option> |
| 37 | <option value="solutions">Solutions</option> |
| 38 | <option value="skills">Skills</option> |
| 39 | </select> |
| 40 | </div> |
| 41 | |
| 42 | <div class="filter-group-inline filter-limit"> |
| 43 | <label for="limit-input">Limit:</label> |
| 44 | <input type="number" id="limit-input" x-model.number="$store.memoryDashboardStore.limit" |
| 45 | min="10" max="1000" step="10" /> |
| 46 | </div> |
| 47 | |
| 48 | <div class="filter-threshold"> |
| 49 | <label for="threshold-input">Threshold: <strong |
| 50 | x-text="$store.memoryDashboardStore.threshold.toFixed(2)"></strong></label> |
| 51 | <input type="range" id="threshold-input" x-model.number="$store.memoryDashboardStore.threshold" |
| 52 | min="0" max="1" step="0.01" /> |
| 53 | </div> |
| 54 | |
| 55 | <input type="text" id="search-input" x-model="$store.memoryDashboardStore.searchQuery" |
| 56 | placeholder="Search memory content..." |
| 57 | @keyup.enter="$store.memoryDashboardStore.searchMemories()" /> |
| 58 | |
| 59 | <button class="btn btn-ok btn-search" @click="$store.memoryDashboardStore.searchMemories()" |
| 60 | :disabled="$store.memoryDashboardStore.loading || $store.memoryDashboardStore.loadingSubdirs"> |
| 61 | <span x-show="!$store.memoryDashboardStore.initializingMemory">Search</span> |
| 62 | <span x-show="$store.memoryDashboardStore.initializingMemory">Init...</span> |
| 63 | </button> |
| 64 | |
| 65 | <button class="btn btn-cancel btn-clear" @click="$store.memoryDashboardStore.clearSearch()"> |
| 66 | Clear |
| 67 | </button> |
| 68 | </div> |
| 69 | |
| 70 | <!-- Loading state --> |
| 71 | <div x-show="$store.memoryDashboardStore.loading" class="loading-state"> |
| 72 | <div class="loading-spinner"></div> |
| 73 | <span x-show="!$store.memoryDashboardStore.initializingMemory">Searching memories...</span> |
| 74 | <span x-show="$store.memoryDashboardStore.initializingMemory">Initializing memory database...</span> |
| 75 | </div> |
| 76 | |
| 77 | <!-- Error state --> |
| 78 | <div x-show="$store.memoryDashboardStore.error" class="error-state"> |
| 79 | <span x-text="$store.memoryDashboardStore.error"></span> |
| 80 | </div> |
| 81 | |
| 82 | <!-- Memory table --> |
| 83 | <div x-show="!$store.memoryDashboardStore.loading && !$store.memoryDashboardStore.error" |
| 84 | class="data-table-container data-table-container-standalone memory-table-container"> |
| 85 | |
| 86 | <!-- Status Bar --> |
| 87 | <div class="data-status-bar" x-show="!$store.memoryDashboardStore.loading"> |
| 88 | <div class="status-info"> |
| 89 | <span class="status-item"> |
| 90 | <x-icon name="database"></x-icon> |
| 91 | Total: <strong x-text="$store.memoryDashboardStore.totalDbCount"></strong> |
| 92 | </span> |
| 93 | <span class="status-separator">•</span> |
| 94 | <span class="status-item"> |
| 95 | Filtered: <strong x-text="$store.memoryDashboardStore.totalCount"></strong> |
| 96 | </span> |
| 97 | <span class="status-separator">•</span> |
| 98 | <span class="status-item"> |
| 99 | Knowledge: <strong x-text="$store.memoryDashboardStore.knowledgeCount"></strong> |
| 100 | </span> |
| 101 | <span class="status-separator">•</span> |
| 102 | <span class="status-item"> |
| 103 | Conversation: <strong x-text="$store.memoryDashboardStore.conversationCount"></strong> |
| 104 | </span> |
| 105 | </div> |
| 106 | |
| 107 | <!-- Pagination --> |
| 108 | <div class="status-pagination" x-show="$store.memoryDashboardStore.totalPages > 1"> |
| 109 | <button class="btn btn-icon" @click="$store.memoryDashboardStore.prevPage()" |
| 110 | :disabled="$store.memoryDashboardStore.currentPage === 1" title="Previous Page"> |
| 111 | <x-icon name="chevron_left"></x-icon> |
| 112 | </button> |
| 113 | <div class="page-input-group"> |
| 114 | <label>Page</label> |
| 115 | <input type="number" class="page-input" |
| 116 | x-model.number="$store.memoryDashboardStore.currentPage" |
| 117 | @change="$store.memoryDashboardStore.goToPage($store.memoryDashboardStore.currentPage)" |
| 118 | @keyup.enter="$store.memoryDashboardStore.goToPage($store.memoryDashboardStore.currentPage)" |
| 119 | :min="1" :max="$store.memoryDashboardStore.totalPages" /> |
| 120 | <span class="page-total">of <strong |
| 121 | x-text="$store.memoryDashboardStore.totalPages"></strong></span> |
| 122 | </div> |
| 123 | <button class="btn btn-icon" @click="$store.memoryDashboardStore.nextPage()" |
| 124 | :disabled="$store.memoryDashboardStore.currentPage === $store.memoryDashboardStore.totalPages" |
| 125 | title="Next Page"> |
| 126 | <x-icon name="chevron_right"></x-icon> |
| 127 | </button> |
| 128 | </div> |
| 129 | </div> |
| 130 | |
| 131 | <!-- Mass action toolbar --> |
| 132 | <div x-show="$store.memoryDashboardStore.selectedCount > 0" class="mass-action-toolbar"> |
| 133 | <div class="selection-info"> |
| 134 | <span x-text="$store.memoryDashboardStore.selectedCount"></span> memories selected |
| 135 | </div> |
| 136 | |
| 137 | <div class="mass-actions"> |
| 138 | <button class="btn btn-mass copy" @click="$store.memoryDashboardStore.bulkCopyMemories()" |
| 139 | title="Copy Selected Content"> |
| 140 | <x-icon name="content_copy"></x-icon> |
| 141 | Copy |
| 142 | </button> |
| 143 | |
| 144 | <button class="btn btn-mass export" |
| 145 | @click="$store.memoryDashboardStore.bulkExportMemories()" |
| 146 | title="Export Selected Memories"> |
| 147 | <x-icon name="download"></x-icon> |
| 148 | Export |
| 149 | </button> |
| 150 | |
| 151 | <button class="btn btn-mass delete" |
| 152 | @click="$confirmClick($event, () => $store.memoryDashboardStore.bulkDeleteMemories())" |
| 153 | title="Delete Selected Memories"> |
| 154 | <x-icon name="delete"></x-icon> |
| 155 | Delete |
| 156 | </button> |
| 157 | |
| 158 | <button class="btn btn-mass clear" @click="$store.memoryDashboardStore.clearSelection()" |
| 159 | title="Clear Selection"> |
| 160 | <x-icon name="close"></x-icon> |
| 161 | Clear |
| 162 | </button> |
| 163 | </div> |
| 164 | </div> |
| 165 | |
| 166 | <div class="table-wrapper"> |
| 167 | <table class="data-table memory-table"> |
| 168 | <thead> |
| 169 | <tr> |
| 170 | <th class="col-select"> |
| 171 | <input type="checkbox" :checked="$store.memoryDashboardStore.allSelected" |
| 172 | :indeterminate="$store.memoryDashboardStore.someSelected && !$store.memoryDashboardStore.allSelected" |
| 173 | @change="$store.memoryDashboardStore.toggleSelectAll()" |
| 174 | title="Select/Deselect All" /> |
| 175 | </th> |
| 176 | <th class="col-metadata">Metadata</th> |
| 177 | <th class="col-preview">Preview</th> |
| 178 | <th class="col-actions"></th> |
| 179 | </tr> |
| 180 | </thead> |
| 181 | <tbody> |
| 182 | <template x-for="memory in $store.memoryDashboardStore.paginatedMemories" |
| 183 | :key="memory.id"> |
| 184 | <tr class="memory-row" :class="{'selected': memory.selected}" |
| 185 | @click="$store.memoryDashboardStore.showMemoryDetails(memory)" |
| 186 | style="cursor: pointer;"> |
| 187 | <!-- Selection checkbox --> |
| 188 | <td class="select-cell" @click.stop="memory.selected = !memory.selected"> |
| 189 | <input type="checkbox" x-model="memory.selected" /> |
| 190 | </td> |
| 191 | |
| 192 | <!-- Metadata (merged Area, Timestamp, Source) --> |
| 193 | <td class="metadata-cell"> |
| 194 | <div class="metadata-info"> |
| 195 | <div class="metadata-row"> |
| 196 | <span class="area-badge" |
| 197 | :style="`background-color: ${$store.memoryDashboardStore.getAreaColor(memory.area)}`" |
| 198 | x-text="(memory.area || 'UNKNOWN').toUpperCase()"></span> |
| 199 | </div> |
| 200 | <div class="metadata-row"> |
| 201 | <template x-if="memory.knowledge_source"> |
| 202 | <span class="source-type knowledge">Knowledge</span> |
| 203 | </template> |
| 204 | <template x-if="!memory.knowledge_source"> |
| 205 | <span class="source-type conversation">Conversation</span> |
| 206 | </template> |
| 207 | </div> |
| 208 | <div class="metadata-row metadata-timestamp"> |
| 209 | <span |
| 210 | x-text="$store.memoryDashboardStore.formatTimestamp(memory.timestamp, true)" |
| 211 | :title="$store.memoryDashboardStore.formatTimestamp(memory.timestamp, false)"></span> |
| 212 | </div> |
| 213 | |
| 214 | </div> |
| 215 | </td> |
| 216 | |
| 217 | <!-- Content preview --> |
| 218 | <td class="preview-cell"> |
| 219 | <div class="content-preview" |
| 220 | x-text="memory.content_full.substring(0, 200) + (memory.content_full.length > 200 ? '...' : '')"> |
| 221 | </div> |
| 222 | <div class="tags" x-show="memory.tags && memory.tags.length > 0"> |
| 223 | <template x-for="tag in memory.tags" :key="tag"> |
| 224 | <span class="tag" x-text="tag"></span> |
| 225 | </template> |
| 226 | </div> |
| 227 | </td> |
| 228 | |
| 229 | <!-- Actions --> |
| 230 | <td class="actions-cell" @click.stop> |
| 231 | <div class="actions-wrapper"> |
| 232 | <button class="btn btn-action copy" |
| 233 | @click="$store.memoryDashboardStore.copyToClipboard($store.memoryDashboardStore.formatMemoryForCopy(memory))" |
| 234 | title="Copy Memory"> |
| 235 | <x-icon name="content_copy"></x-icon> |
| 236 | </button> |
| 237 | |
| 238 | <button class="btn btn-action delete" |
| 239 | @click="$confirmClick($event, () => $store.memoryDashboardStore.deleteMemory(memory))" |
| 240 | title="Delete Memory"> |
| 241 | <x-icon name="delete"></x-icon> |
| 242 | </button> |
| 243 | </div> |
| 244 | </td> |
| 245 | </tr> |
| 246 | </template> |
| 247 | </tbody> |
| 248 | </table> |
| 249 | |
| 250 | |
| 251 | |
| 252 | </div> |
| 253 | |
| 254 | <!-- Mass action toolbar --> |
| 255 | <div x-show="$store.memoryDashboardStore.selectedCount > 0" class="mass-action-toolbar"> |
| 256 | <div class="selection-info"> |
| 257 | <span x-text="$store.memoryDashboardStore.selectedCount"></span> memories selected |
| 258 | </div> |
| 259 | |
| 260 | <div class="mass-actions"> |
| 261 | <button class="btn btn-mass copy" @click="$store.memoryDashboardStore.bulkCopyMemories()" |
| 262 | title="Copy Selected Content"> |
| 263 | <x-icon name="content_copy"></x-icon> |
| 264 | Copy |
| 265 | </button> |
| 266 | |
| 267 | <button class="btn btn-mass export" |
| 268 | @click="$store.memoryDashboardStore.bulkExportMemories()" |
| 269 | title="Export Selected Memories"> |
| 270 | <x-icon name="download"></x-icon> |
| 271 | Export |
| 272 | </button> |
| 273 | |
| 274 | <button class="btn btn-mass delete" |
| 275 | @click="$confirmClick($event, () => $store.memoryDashboardStore.bulkDeleteMemories())" |
| 276 | title="Delete Selected Memories"> |
| 277 | <x-icon name="delete"></x-icon> |
| 278 | Delete |
| 279 | </button> |
| 280 | |
| 281 | <button class="btn btn-mass clear" @click="$store.memoryDashboardStore.clearSelection()" |
| 282 | title="Clear Selection"> |
| 283 | <x-icon name="close"></x-icon> |
| 284 | Clear |
| 285 | </button> |
| 286 | </div> |
| 287 | </div> |
| 288 | |
| 289 | |
| 290 | <!-- Status Bar --> |
| 291 | <div class="data-status-bar data-status-bar-bottom" x-show="!$store.memoryDashboardStore.loading"> |
| 292 | <div class="status-info"> |
| 293 | <span class="status-item"> |
| 294 | <x-icon name="database"></x-icon> |
| 295 | Total: <strong x-text="$store.memoryDashboardStore.totalDbCount"></strong> |
| 296 | </span> |
| 297 | <span class="status-separator">•</span> |
| 298 | <span class="status-item"> |
| 299 | Filtered: <strong x-text="$store.memoryDashboardStore.totalCount"></strong> |
| 300 | </span> |
| 301 | <span class="status-separator">•</span> |
| 302 | <span class="status-item"> |
| 303 | Knowledge: <strong x-text="$store.memoryDashboardStore.knowledgeCount"></strong> |
| 304 | </span> |
| 305 | <span class="status-separator">•</span> |
| 306 | <span class="status-item"> |
| 307 | Conversation: <strong x-text="$store.memoryDashboardStore.conversationCount"></strong> |
| 308 | </span> |
| 309 | </div> |
| 310 | |
| 311 | <!-- Pagination --> |
| 312 | <div class="status-pagination" x-show="$store.memoryDashboardStore.totalPages > 1"> |
| 313 | <button class="btn btn-icon" @click="$store.memoryDashboardStore.prevPage()" |
| 314 | :disabled="$store.memoryDashboardStore.currentPage === 1" title="Previous Page"> |
| 315 | <x-icon name="chevron_left"></x-icon> |
| 316 | </button> |
| 317 | <div class="page-input-group"> |
| 318 | <label>Page</label> |
| 319 | <input type="number" class="page-input" |
| 320 | x-model.number="$store.memoryDashboardStore.currentPage" |
| 321 | @change="$store.memoryDashboardStore.goToPage($store.memoryDashboardStore.currentPage)" |
| 322 | @keyup.enter="$store.memoryDashboardStore.goToPage($store.memoryDashboardStore.currentPage)" |
| 323 | :min="1" :max="$store.memoryDashboardStore.totalPages" /> |
| 324 | <span class="page-total">of <strong |
| 325 | x-text="$store.memoryDashboardStore.totalPages"></strong></span> |
| 326 | </div> |
| 327 | <button class="btn btn-icon" @click="$store.memoryDashboardStore.nextPage()" |
| 328 | :disabled="$store.memoryDashboardStore.currentPage === $store.memoryDashboardStore.totalPages" |
| 329 | title="Next Page"> |
| 330 | <x-icon name="chevron_right"></x-icon> |
| 331 | </button> |
| 332 | </div> |
| 333 | </div> |
| 334 | |
| 335 | |
| 336 | <!-- No memories message --> |
| 337 | <div x-show="$store.memoryDashboardStore.memories.length === 0 && !$store.memoryDashboardStore.message" |
| 338 | class="data-empty-state"> |
| 339 | No memories found matching the current filters. |
| 340 | </div> |
| 341 | |
| 342 | <!-- Initialization message --> |
| 343 | <div x-show="$store.memoryDashboardStore.message" class="init-message"> |
| 344 | <span x-text="$store.memoryDashboardStore.message"></span> |
| 345 | </div> |
| 346 | |
| 347 | |
| 348 | |
| 349 | </div> |
| 350 | |
| 351 | |
| 352 | |
| 353 | </div> |
| 354 | </template> |
| 355 | </div> |
| 356 | |
| 357 | <style> |
| 358 | /* Modal footer layout */ |
| 359 | .modal-inner.modal-with-footer { |
| 360 | display: flex; |
| 361 | flex-direction: column; |
| 362 | } |
| 363 | .modal-inner.modal-with-footer .modal-scroll { |
| 364 | flex: 1; |
| 365 | min-height: 0; |
| 366 | } |
| 367 | .modal-inner.modal-with-footer .modal-footer { |
| 368 | flex-shrink: 0; |
| 369 | } |
| 370 | |
| 371 | /* Memory-specific: Grid-based filter header layout */ |
| 372 | .memory-filters-header { |
| 373 | display: grid; |
| 374 | grid-template-columns: 35% 25% 10% auto; |
| 375 | grid-template-rows: auto auto; |
| 376 | margin: 0 0 1rem 0; |
| 377 | } |
| 378 | |
| 379 | /* Grid positioning for desktop - 2 rows */ |
| 380 | .filter-memory-dir { |
| 381 | grid-column: 1; |
| 382 | grid-row: 1; |
| 383 | } |
| 384 | .filter-area { |
| 385 | grid-column: 2; |
| 386 | grid-row: 1; |
| 387 | } |
| 388 | .filter-limit { |
| 389 | grid-column: 3; |
| 390 | grid-row: 1; |
| 391 | } |
| 392 | .filter-threshold { |
| 393 | grid-column: 4; |
| 394 | grid-row: 2; |
| 395 | } |
| 396 | #search-input { |
| 397 | grid-column: 1 / 3; |
| 398 | grid-row: 2; |
| 399 | flex: 1; |
| 400 | border: 1px solid var(--color-border); |
| 401 | font-size: 0.9rem; |
| 402 | height: 38px; |
| 403 | } |
| 404 | #search-input:focus { |
| 405 | outline: none; |
| 406 | border-color: var(--color-primary); |
| 407 | background: var(--color-input-focus); |
| 408 | } |
| 409 | .btn-search { |
| 410 | grid-column: 3; |
| 411 | grid-row: 2; |
| 412 | justify-content: center; |
| 413 | } |
| 414 | .btn-clear { |
| 415 | grid-column: 4; |
| 416 | grid-row: 1; |
| 417 | justify-self: end; |
| 418 | } |
| 419 | |
| 420 | /* Memory-specific filter overrides */ |
| 421 | .memory-filters-header .filter-group-inline { |
| 422 | flex: 1; |
| 423 | } |
| 424 | .memory-filters-header .filter-group-inline select, |
| 425 | .memory-filters-header .filter-group-inline input { |
| 426 | flex: 0 auto; |
| 427 | } |
| 428 | .memory-filters-header .filter-group-inline.filter-limit { |
| 429 | flex: 0 0 auto; |
| 430 | } |
| 431 | .filter-limit input { |
| 432 | flex: 0 0 150% !important; |
| 433 | } |
| 434 | |
| 435 | /* Memory-specific: Table layout overrides */ |
| 436 | .memory-table { |
| 437 | table-layout: fixed; |
| 438 | } |
| 439 | .memory-table th, |
| 440 | .memory-table td { |
| 441 | padding: 1rem 0.75rem; |
| 442 | vertical-align: top; |
| 443 | } |
| 444 | .memory-table th { |
| 445 | position: sticky; |
| 446 | top: 0; |
| 447 | z-index: 10; |
| 448 | border-bottom: 2px solid var(--color-border); |
| 449 | } |
| 450 | .memory-table tbody tr.memory-row > td { |
| 451 | height: 5em; |
| 452 | } |
| 453 | |
| 454 | /* Memory-specific column widths */ |
| 455 | .col-select { |
| 456 | width: 5%; |
| 457 | text-align: center; |
| 458 | padding: 0.65rem 0.5rem !important; |
| 459 | } |
| 460 | .col-metadata { |
| 461 | width: 10em; |
| 462 | } |
| 463 | .col-actions { |
| 464 | width: 4em; |
| 465 | } |
| 466 | .col-select input[type="checkbox"] { |
| 467 | cursor: pointer; |
| 468 | transform: scale(1.2); |
| 469 | } |
| 470 | |
| 471 | /* Memory-specific: Metadata display */ |
| 472 | .metadata-cell { |
| 473 | overflow: visible; |
| 474 | text-wrap: wrap; |
| 475 | word-wrap: break-word; |
| 476 | } |
| 477 | .preview-cell { |
| 478 | overflow: visible; |
| 479 | text-wrap: wrap; |
| 480 | word-wrap: break-word; |
| 481 | } |
| 482 | .metadata-info { |
| 483 | display: flex; |
| 484 | flex-direction: column; |
| 485 | gap: 0.5rem; |
| 486 | height: 5.5em; |
| 487 | overflow: hidden; |
| 488 | } |
| 489 | .metadata-row { |
| 490 | display: flex; |
| 491 | align-items: center; |
| 492 | gap: 0.5rem; |
| 493 | } |
| 494 | .metadata-timestamp { |
| 495 | font-size: 0.85rem; |
| 496 | color: var(--color-text); |
| 497 | font-family: monospace; |
| 498 | } |
| 499 | |
| 500 | /* Memory-specific: Area badge */ |
| 501 | .area-badge { |
| 502 | color: white; |
| 503 | padding: 0.35rem 0.75rem; |
| 504 | border-radius: 16px; |
| 505 | font-size: 0.75rem; |
| 506 | font-weight: bold; |
| 507 | text-transform: uppercase; |
| 508 | } |
| 509 | |
| 510 | /* Memory-specific: Source type badge */ |
| 511 | .source-type { |
| 512 | padding: 0.25rem 0.5rem; |
| 513 | border-radius: var(--border-radius); |
| 514 | font-size: 0.75rem; |
| 515 | font-weight: 500; |
| 516 | text-align: center; |
| 517 | border: 1px solid; |
| 518 | white-space: nowrap; |
| 519 | flex-shrink: 0; |
| 520 | } |
| 521 | |
| 522 | /* Memory-specific: Content preview */ |
| 523 | .content-preview { |
| 524 | height: 5.5em; |
| 525 | overflow: hidden; |
| 526 | word-wrap: break-word; |
| 527 | overflow-wrap: break-word; |
| 528 | text-wrap: wrap; |
| 529 | } |
| 530 | |
| 531 | /* Memory-specific: Tags */ |
| 532 | .tags { |
| 533 | display: flex; |
| 534 | gap: 0.25rem; |
| 535 | margin-top: 0.5rem; |
| 536 | flex-wrap: wrap; |
| 537 | } |
| 538 | .tag { |
| 539 | background: var(--color-panel); |
| 540 | border: 1px solid var(--color-border); |
| 541 | padding: 0.2rem 0.4rem; |
| 542 | border-radius: 6px; |
| 543 | font-size: 0.7rem; |
| 544 | color: var(--color-text); |
| 545 | opacity: 0.8; |
| 546 | } |
| 547 | |
| 548 | /* Memory-specific: Selection state */ |
| 549 | .memory-row.selected { |
| 550 | background: var(--color-panel); |
| 551 | border-left: 3px solid var(--color-primary); |
| 552 | } |
| 553 | .select-cell { |
| 554 | text-align: center; |
| 555 | padding: 0.65rem 0.5rem !important; |
| 556 | } |
| 557 | .select-cell input[type="checkbox"] { |
| 558 | cursor: pointer; |
| 559 | transform: scale(1.2); |
| 560 | } |
| 561 | |
| 562 | /* Memory-specific: Actions cell vertical layout */ |
| 563 | .actions-cell { |
| 564 | padding: 0 !important; |
| 565 | position: relative; |
| 566 | } |
| 567 | .memory-table .actions-wrapper { |
| 568 | position: absolute; |
| 569 | top: 0; |
| 570 | left: 0; |
| 571 | right: 0; |
| 572 | bottom: 0; |
| 573 | flex-direction: column; |
| 574 | justify-content: center; |
| 575 | } |
| 576 | |
| 577 | /* Responsive design - Memory-specific */ |
| 578 | @media (max-width: 870px) { |
| 579 | .memory-dashboard { |
| 580 | padding: 0.5rem; |
| 581 | } |
| 582 | |
| 583 | /* Switch to flex layout on mobile */ |
| 584 | .memory-filters-header { |
| 585 | display: flex; |
| 586 | flex-wrap: wrap; |
| 587 | padding: 0.75rem; |
| 588 | } |
| 589 | .content-preview, |
| 590 | .metadata-info { |
| 591 | height: 6em; |
| 592 | } |
| 593 | |
| 594 | /* Reset grid positioning */ |
| 595 | .filter-memory-dir, |
| 596 | .filter-area, |
| 597 | .filter-limit, |
| 598 | .filter-threshold, |
| 599 | #search-input, |
| 600 | .btn-search, |
| 601 | .btn-clear { |
| 602 | grid-column: auto; |
| 603 | grid-row: auto; |
| 604 | } |
| 605 | |
| 606 | /* Mobile order and layout */ |
| 607 | .filter-memory-dir { |
| 608 | order: 1; |
| 609 | flex: 1 1 100%; |
| 610 | } |
| 611 | .filter-area { |
| 612 | order: 2; |
| 613 | flex: 1 1 100%; |
| 614 | } |
| 615 | .filter-limit { |
| 616 | order: 3; |
| 617 | flex: 1 1 100%; |
| 618 | } |
| 619 | .filter-threshold { |
| 620 | order: 4; |
| 621 | flex: 40%; |
| 622 | flex-direction: column; |
| 623 | align-items: stretch; |
| 624 | gap: 0.5rem; |
| 625 | padding: 0; |
| 626 | } |
| 627 | .filter-threshold label { |
| 628 | font-size: 0.9rem; |
| 629 | width: 100%; |
| 630 | display: flex; |
| 631 | justify-content: space-between; |
| 632 | } |
| 633 | .filter-threshold input[type="range"] { |
| 634 | width: 100%; |
| 635 | } |
| 636 | #search-input { |
| 637 | order: 5; |
| 638 | flex: auto; |
| 639 | width: 100%; |
| 640 | min-height: 42px; |
| 641 | } |
| 642 | .btn-clear { |
| 643 | order: 6; |
| 644 | flex: 40%; |
| 645 | min-width: 80px; |
| 646 | padding: 0; |
| 647 | min-height: 42px; |
| 648 | justify-content: center; |
| 649 | } |
| 650 | .btn-search { |
| 651 | order: 7; |
| 652 | flex: 40%; |
| 653 | min-height: 42px; |
| 654 | padding: 0 1rem; |
| 655 | min-width: 80px; |
| 656 | } |
| 657 | |
| 658 | .memory-filters-header .filter-group-inline { |
| 659 | width: 100%; |
| 660 | flex-direction: row; |
| 661 | align-items: center; |
| 662 | gap: 0.5rem; |
| 663 | } |
| 664 | .memory-filters-header .filter-group-inline label { |
| 665 | font-size: 0.9rem; |
| 666 | margin-bottom: 0.25rem; |
| 667 | } |
| 668 | .memory-filters-header .filter-group-inline select, |
| 669 | .memory-filters-header .filter-group-inline input { |
| 670 | height: 42px; |
| 671 | font-size: 1rem; |
| 672 | } |
| 673 | .memory-filters-header .filter-group-inline.filter-limit { |
| 674 | flex: 33%; |
| 675 | } |
| 676 | .filter-limit input { |
| 677 | flex: 1; |
| 678 | } |
| 679 | |
| 680 | .data-status-bar { |
| 681 | flex-direction: column; |
| 682 | gap: 0.75rem; |
| 683 | } |
| 684 | .status-info { |
| 685 | width: 100%; |
| 686 | justify-content: center; |
| 687 | flex-wrap: wrap; |
| 688 | gap: 0.5rem 1rem; |
| 689 | } |
| 690 | .status-info .material-symbols-outlined { |
| 691 | font-size: 18px; |
| 692 | } |
| 693 | .status-pagination { |
| 694 | width: 100%; |
| 695 | justify-content: center; |
| 696 | padding-top: 0.5rem; |
| 697 | border-top: 1px solid var(--color-border); |
| 698 | } |
| 699 | |
| 700 | .memory-table th, |
| 701 | .memory-table td { |
| 702 | padding: 0.5rem 0.25rem; |
| 703 | font-size: 0.85rem; |
| 704 | } |
| 705 | .actions-cell { |
| 706 | min-width: 60px; |
| 707 | width: 60px; |
| 708 | } |
| 709 | .col-select { |
| 710 | width: 8%; |
| 711 | } |
| 712 | .col-metadata { |
| 713 | width: 27%; |
| 714 | } |
| 715 | .col-preview { |
| 716 | width: 55%; |
| 717 | } |
| 718 | .col-actions { |
| 719 | width: 10%; |
| 720 | } |
| 721 | } |
| 722 | </style> |
| 723 | </template> |
| 724 | </div> |
| 725 | </body> |
| 726 | </html> |