PHP Classes

File: templates/netmail.twig

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   templates/netmail.twig   Download  
File: templates/netmail.twig
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 34,884 bytes
 

Contents

Class file image Download
{% extends "base.twig" %} {% block title %}{{ t('ui.netmail.title', {}, locale, ['common']) }} - {{ parent() }}{% endblock %} {% block content %} <div class="d-flex justify-content-between align-items-center mb-4"> <h2> <i class="fas fa-envelope"></i> {{ t('ui.netmail.title', {}, locale, ['common']) }} </h2> <div class="d-flex gap-2"> <button class="btn btn-fidonet" onclick="composeMessage('netmail')"> <i class="fas fa-plus"></i> {{ t('ui.netmail.compose', {}, locale, ['common']) }} </button> {% if ai_assistant_enabled %} {# <button class="btn btn-outline-secondary" onclick="openAiAssistant(typeof currentMessageId !== 'undefined' ? currentMessageId : null, 'netmail')"> <i class="fas fa-robot me-1"></i>{{ t('ui.ai_assistant.button', {}, locale, ['common']) }} </button> #} {% endif %} </div> </div> <div class="row"> <div class="col-lg-9"> <div class="card"> <div class="card-header"> <div class="d-flex flex-column flex-sm-row justify-content-between align-items-start align-items-sm-center gap-2"> <h6 class="mb-0 d-none d-sm-block">{{ t('ui.netmail.messages', {}, locale, ['common']) }}</h6> <div class="d-flex align-items-center gap-2"> <div id="bulkActions" class="d-none"> <button type="button" class="btn btn-outline-danger btn-sm" onclick="deleteSelectedMessages()" disabled> <i class="fas fa-trash"></i> {{ t('ui.netmail.delete_selected', {}, locale, ['common']) }} (<span id="selectedCount">0</span>) </button> </div> <div class="d-flex gap-2 filter-controls"> <div class="btn-group btn-group-sm flex-nowrap" role="group"> <input type="radio" class="btn-check" name="filter" id="all" value="all" checked> <label class="btn btn-outline-secondary" for="all">{{ t('ui.common.all', {}, locale, ['common']) }}</label> <input type="radio" class="btn-check" name="filter" id="unread" value="unread"> <label class="btn btn-outline-secondary" for="unread">{{ t('ui.common.unread', {}, locale, ['common']) }}</label> <input type="radio" class="btn-check" name="filter" id="sent" value="sent"> <label class="btn btn-outline-secondary" for="sent">{{ t('ui.common.sent', {}, locale, ['common']) }}</label> <input type="radio" class="btn-check" name="filter" id="saved" value="saved"> <label class="btn btn-outline-secondary" for="saved">{{ t('ui.netmail.saved_items', {}, locale, ['common']) }} <span class="badge bg-secondary ms-1" id="savedFilterBadge" style="display:none;"></span></label> <input type="radio" class="btn-check" name="filter" id="drafts" value="drafts"> <label class="btn btn-outline-secondary" for="drafts">{{ t('ui.common.drafts', {}, locale, ['common']) }}</label> </div> <div class="dropdown"> <button type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown"> <i class="fas fa-sort"></i> </button> <ul class="dropdown-menu"> <li><a class="dropdown-item sort-option" data-sort="date_desc" href="#" onclick="sortMessages('date_desc')">{{ t('ui.common.sort.newest_first', {}, locale, ['common']) }}</a></li> <li><a class="dropdown-item sort-option" data-sort="date_asc" href="#" onclick="sortMessages('date_asc')">{{ t('ui.common.sort.oldest_first', {}, locale, ['common']) }}</a></li> <li><a class="dropdown-item sort-option" data-sort="subject" href="#" onclick="sortMessages('subject')">{{ t('ui.common.sort.by_subject', {}, locale, ['common']) }}</a></li> <li><a class="dropdown-item sort-option" data-sort="author" href="#" onclick="sortMessages('author')">{{ t('ui.common.sort.by_author', {}, locale, ['common']) }}</a></li> <li><hr class="dropdown-divider"></li> <li><a class="dropdown-item" href="#" onclick="toggleThreading()"> <i class="fas fa-project-diagram"></i> <span id="threadingToggleText">{{ t('ui.common.threading.show_threaded', {}, locale, ['common']) }}</span> </a></li> </ul> </div> <button type="button" class="btn btn-outline-secondary btn-sm" onclick="toggleSelectMode()" id="selectModeBtn"> <i class="fas fa-check-square"></i> {{ t('ui.common.select', {}, locale, ['common']) }} </button> </div> </div> </div> </div> <div class="card-body p-0"> <div id="messagesContainer"> <div class="loading-spinner"> <i class="fas fa-spinner fa-spin me-2"></i> {{ t('ui.common.loading_messages', {}, locale, ['common']) }} </div> </div> </div> <div class="card-footer"> <nav id="pagination"> <!-- Pagination will be inserted here --> </nav> </div> </div> </div> <div class="col-lg-3"> <div class="card"> <div class="card-header"> <h6 class="mb-0">{{ t('ui.common.search', {}, locale, ['common']) }}</h6> </div> <div class="card-body"> <div class="mb-3"> <input type="text" class="form-control" id="searchInput" placeholder="{{ t('ui.common.search_messages_placeholder', {}, locale, ['common']) }}"> </div> <div class="d-flex gap-2"> <button class="btn btn-outline-primary btn-sm flex-fill" onclick="searchMessages()"> <i class="fas fa-search"></i> {{ t('ui.common.search', {}, locale, ['common']) }} </button> <button class="btn btn-outline-secondary btn-sm" onclick="openAdvancedSearch()" title="{{ t('ui.common.advanced_search', {}, locale, ['common']) }}"> <i class="fas fa-sliders-h"></i> </button> </div> </div> </div> <div class="card mt-3"> <div class="card-header"> <div class="d-flex justify-content-between align-items-center"> <h6 class="mb-0">{{ t('ui.address_book.title', {}, locale, ['common']) }}</h6> <button class="btn btn-sm btn-outline-primary" onclick="showAddAddressModal()"> <i class="fas fa-plus"></i> </button> </div> </div> <div class="card-body"> <div class="mb-2"> <input type="text" class="form-control form-control-sm" id="addressBookSearch" placeholder="{{ t('ui.address_book.search_placeholder', {}, locale, ['common']) }}"> </div> <div id="addressBookList" style="max-height: 200px; overflow-y: auto;"> <div class="text-center text-muted py-2"> <i class="fas fa-spinner fa-spin"></i> {{ t('ui.common.loading', {}, locale, ['common']) }} </div> </div> <div class="mt-2"> <small class="text-muted" id="addressBookStats">0 {{ t('ui.address_book.entries', {}, locale, ['common']) }}</small> </div> </div> </div> <div class="card mt-3"> <div class="card-header"> <h6 class="mb-0">{{ t('ui.netmail.quick_stats', {}, locale, ['common']) }}</h6> </div> <div class="card-body"> <dl class="row mb-0"> <dt class="col-6">{{ t('ui.common.total', {}, locale, ['common']) }}:</dt> <dd class="col-6" id="totalCount">-</dd> <dt class="col-6">{{ t('ui.common.unread', {}, locale, ['common']) }}:</dt> <dd class="col-6" id="unreadCount">-</dd> <dt class="col-6">{{ t('ui.common.sent', {}, locale, ['common']) }}:</dt> <dd class="col-6" id="sentCount">-</dd> <dt class="col-6">{{ t('ui.netmail.saved_items', {}, locale, ['common']) }}:</dt> <dd class="col-6" id="savedCount">-</dd> </dl> </div> </div> </div> </div> <div id="messageContextMenu" class="dropdown-menu" style="display:none; position:absolute; z-index:1080;"> <button type="button" class="dropdown-item" onclick="replyFromContextMenu()"> <i class="fas fa-reply me-2"></i>{{ t('ui.common.reply', {}, 'common') }} </button> <button type="button" class="dropdown-item" onclick="repostFromContextMenu()"> <i class="fas fa-share me-2"></i>{{ t('ui.common.repost', {}, 'common') }} </button> <button type="button" class="dropdown-item" onclick="viewConversationFromContextMenu()"> <i class="fas fa-comments me-2"></i>{{ t('ui.common.view_conversation', {}, locale, ['common']) }} </button> <button type="button" class="dropdown-item" id="messageContextMenuSave" onclick="saveFromContextMenu()"> <i class="fas fa-bookmark me-2"></i><span id="messageContextMenuSaveLabel">{{ t('ui.common.save_for_later', {}, locale, ['common']) }}</span> </button> <button type="button" class="dropdown-item" onclick="downloadMessageFromContextMenu()"> <i class="fas fa-download me-2"></i>{{ t('ui.common.download_message', {}, locale, ['common']) }} </button> {% if current_user.email %} <button type="button" class="dropdown-item" onclick="forwardMessageToEmailFromContextMenu()"> <i class="fas fa-envelope me-2"></i>{{ t('ui.common.forward_to_me_by_email', {}, locale, ['common']) }} </button> {% endif %} </div> <!-- Message View Modal --> <div class="modal fade" id="messageModal" tabindex="-1"> <div class="modal-dialog modal-lg modal-message-reader{% if appearance.message_reader.scrollable_body %} modal-dialog-scrollable message-reader-scrollable{% endif %}"> <div class="modal-content"> <div class="modal-header"> <div class="d-flex align-items-center gap-2"> <button type="button" class="btn btn-outline-secondary btn-sm" id="prevMessageBtn" onclick="navigateMessage(-1)" title="{{ t('ui.common.previous_message', {}, locale, ['common']) }}"> <i class="fas fa-chevron-left"></i> </button> <button type="button" class="btn btn-outline-secondary btn-sm" id="nextMessageBtn" onclick="navigateMessage(1)" title="{{ t('ui.common.next_message', {}, locale, ['common']) }}"> <i class="fas fa-chevron-right"></i> </button> <button type="button" class="btn btn-outline-secondary btn-sm" id="editMessageButton" onclick="openEditMessage()" title="{{ t('ui.common.edit', {}, locale, ['common']) }}"> <i class="fas fa-pencil-alt"></i> </button> <button type="button" class="btn btn-outline-secondary btn-sm" id="toggleHeaders" onclick="toggleKludgeLines()" title="{{ t('ui.common.show_kludge_lines', {}, locale, ['common']) }}"> <i class="fas fa-code" id="toggleIcon"></i> </button> <button type="button" class="btn btn-outline-secondary btn-sm" onclick="printMessage()" title="{{ t('ui.common.print', {}, locale, ['common']) }}"> <i class="fas fa-print"></i> </button> <button type="button" class="btn btn-outline-secondary btn-sm" onclick="toggleKeyboardHelp()" title="{{ t('ui.echomail.shortcuts.title', {}, locale, ['common']) }}"> <i class="fas fa-keyboard"></i> </button> </div> <h5 class="modal-title" id="messageSubject">{{ t('ui.common.message', {}, locale, ['common']) }}</h5> <button type="button" class="btn btn-outline-secondary btn-sm me-2" id="fullscreenToggle" onclick="toggleModalFullscreen()" title="{{ t('ui.common.toggle_fullscreen', {}, locale, ['common']) }}"> <i class="fas fa-expand"></i> </button> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body"> <div id="messageContent"> <div class="loading-spinner"> <i class="fas fa-spinner fa-spin me-2"></i> {{ t('ui.common.loading_message', {}, locale, ['common']) }} </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-danger btn-compact-label" id="deleteButton"> <i class="fas fa-trash"></i> <span class="btn-text">{{ t('ui.common.delete', {}, locale, ['common']) }}</span> </button> <button type="button" class="btn btn-secondary btn-compact-label" data-bs-dismiss="modal"> <i class="fas fa-times"></i> <span class="btn-text">{{ t('ui.common.close', {}, locale, ['common']) }}</span> </button> <button type="button" class="btn btn-outline-warning btn-compact-label" id="modalSaveButton"> <i class="fas fa-bookmark"></i> <span class="btn-text" id="modalSaveText">{{ t('ui.common.save', {}, locale, ['common']) }}</span> </button> <button type="button" class="btn btn-fidonet btn-compact-label" id="replyButton"> <i class="fas fa-reply"></i> <span class="btn-text">{{ t('ui.common.reply', {}, locale, ['common']) }}</span> </button> <button type="button" class="btn btn-outline-primary btn-compact-label" id="repostButton"> <i class="fas fa-share"></i> <span class="btn-text">{{ t('ui.common.repost', {}, locale, ['common']) }}</span> </button> </div> {# Keyboard shortcuts help overlay #} <div id="keyboardHelpOverlay" style="display:none; position:absolute; inset:0; z-index:20; background:rgba(0,0,0,0.82); padding:2rem; overflow-y:auto;"> <div class="mx-auto" style="max-width:480px;"> <h5 class="text-white mb-3"><i class="fas fa-keyboard me-2"></i>{{ t('ui.echomail.shortcuts.title', {}, locale, ['common']) }}</h5> <table class="table table-sm table-dark table-borderless mb-3"> <tbody> <tr> <td class="text-center" style="width:120px;"> <kbd>&larr;</kbd> <kbd>&rarr;</kbd> </td> <td>{{ t('ui.echomail.shortcuts.prev_next', {}, locale, ['common']) }}</td> </tr> <tr> <td class="text-center"><kbd>A</kbd></td> <td>{{ t('ui.echomail.shortcuts.cycle_viewer_mode', {}, locale, ['common']) }}</td> </tr> <tr> <td class="text-center"><kbd>D</kbd></td> <td>{{ t('ui.echomail.shortcuts.download', {}, locale, ['common']) }}</td> </tr> <tr> <td class="text-center"><kbd>F</kbd></td> <td>{{ t('ui.echomail.shortcuts.fullscreen', {}, locale, ['common']) }}</td> </tr> <tr> <td class="text-center"><kbd>?</kbd> <kbd>H</kbd></td> <td>{{ t('ui.echomail.shortcuts.help', {}, locale, ['common']) }}</td> </tr> <tr> <td class="text-center"><kbd>Esc</kbd></td> <td>{{ t('ui.echomail.shortcuts.close', {}, locale, ['common']) }}</td> </tr> </tbody> </table> <p class="text-muted small mb-0">{{ t('ui.echomail.shortcuts.dismiss', {}, locale, ['common']) }}</p> </div> </div> </div> </div> </div> <!-- Advanced Search Modal --> <div class="modal fade" id="advancedSearchModal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title"><i class="fas fa-sliders-h me-2"></i>{{ t('ui.common.advanced_search.title', {}, locale, ['common']) }}</h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body"> <p class="text-muted small mb-3">{{ t('ui.common.advanced_search.help', {}, locale, ['common']) }}</p> <div class="mb-3"> <label for="advSearchFromName" class="form-label">{{ t('ui.common.advanced_search.from_name', {}, locale, ['common']) }}</label> <input type="text" class="form-control" id="advSearchFromName" placeholder="{{ t('ui.common.advanced_search.from_name_placeholder', {}, locale, ['common']) }}"> </div> <div class="mb-3"> <label for="advSearchSubject" class="form-label">{{ t('ui.common.advanced_search.subject', {}, locale, ['common']) }}</label> <input type="text" class="form-control" id="advSearchSubject" placeholder="{{ t('ui.common.advanced_search.subject_placeholder', {}, locale, ['common']) }}"> </div> <div class="mb-3"> <label for="advSearchBody" class="form-label">{{ t('ui.common.advanced_search.body', {}, locale, ['common']) }}</label> <input type="text" class="form-control" id="advSearchBody" placeholder="{{ t('ui.common.advanced_search.body_placeholder', {}, locale, ['common']) }}"> </div> <div class="mb-3"> <label class="form-label">{{ t('ui.common.advanced_search.date_range', {}, locale, ['common']) }}</label> <div class="d-flex gap-2 align-items-center"> <input type="date" class="form-control" id="advSearchDateFrom"> <span class="text-muted flex-shrink-0">?</span> <input type="date" class="form-control" id="advSearchDateTo"> </div> </div> <div id="advSearchError" class="alert alert-danger d-none"></div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ t('ui.common.cancel', {}, locale, ['common']) }}</button> <button type="button" class="btn btn-primary" onclick="runAdvancedSearch()"> <i class="fas fa-search me-1"></i>{{ t('ui.common.search', {}, locale, ['common']) }} </button> </div> </div> </div> </div> <!-- Address Book Entry Modal --> <div class="modal fade" id="addressBookModal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="addressBookModalTitle">{{ t('ui.address_book.add_entry', {}, locale, ['common']) }}</h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body"> <div id="addressBookModalError" class="alert alert-danger d-none" role="alert"></div> <form id="addressBookForm"> <input type="hidden" id="addressBookEntryId"> <div class="mb-3"> <label for="addressBookName" class="form-label">{{ t('ui.common.name', {}, locale, ['common']) }}</label> <input type="text" class="form-control" id="addressBookName" required placeholder="{{ t('ui.address_book.name_placeholder', {}, locale, ['common']) }}"> <div class="form-text">{{ t('ui.address_book.name_help', {}, locale, ['common']) }}</div> </div> <div class="mb-3"> <label for="addressBookUserId" class="form-label">{{ t('ui.address_book.user_id', {}, locale, ['common']) }}</label> <input type="text" class="form-control" id="addressBookUserId" required placeholder="{{ t('ui.address_book.user_id_placeholder', {}, locale, ['common']) }}"> <div class="form-text">{{ t('ui.address_book.user_id_help', {}, locale, ['common']) }}</div> </div> <div class="mb-3"> <label for="addressBookNodeAddress" class="form-label">{{ t('ui.address_book.node_address', {}, locale, ['common']) }}</label> <input type="text" class="form-control" id="addressBookNodeAddress" required placeholder="{{ t('ui.address_book.node_address_placeholder', {}, locale, ['common']) }}" pattern="^\d+:\d+\/\d+(\.\d+)?$" title="{{ t('ui.address_book.node_address_title', {}, locale, ['common']) }}"> <div class="form-text">{{ t('ui.address_book.node_address_help', {}, locale, ['common']) }}</div> </div> <div class="mb-3"> <label for="addressBookEmail" class="form-label">{{ t('ui.address_book.email_address', {}, locale, ['common']) }} <small class="text-muted">({{ t('ui.common.optional', {}, locale, ['common']) }})</small></label> <input type="email" class="form-control" id="addressBookEmail" placeholder="email@example.com"> <div class="form-text">{{ t('ui.address_book.email_help', {}, locale, ['common']) }}</div> </div> <div class="mb-3"> <label for="addressBookDescription" class="form-label">{{ t('ui.common.description', {}, locale, ['common']) }} <small class="text-muted">({{ t('ui.common.optional', {}, locale, ['common']) }})</small></label> <textarea class="form-control" id="addressBookDescription" rows="3" placeholder="{{ t('ui.address_book.description_placeholder', {}, locale, ['common']) }}"></textarea> </div> {% if crashmail_enabled %} <div class="mb-3"> <div class="form-check"> <input type="checkbox" class="form-check-input" id="addressBookAlwaysCrashmail" name="always_crashmail"> <label class="form-check-label" for="addressBookAlwaysCrashmail"> <i class="fas fa-bolt text-warning me-1"></i>{{ t('ui.address_book.always_crashmail', {}, locale, ['common']) }} </label> <div class="form-text">{{ t('ui.address_book.always_crashmail_help', {}, locale, ['common']) }}</div> </div> </div> {% endif %} </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ t('ui.common.cancel', {}, locale, ['common']) }}</button> <button type="button" class="btn btn-primary" onclick="saveAddressBookEntry()"> <i class="fas fa-save"></i> {{ t('ui.common.save', {}, locale, ['common']) }} </button> </div> </div> </div> </div> <!-- Edit Message Modal --> <div class="modal fade" id="editMessageModal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="editMessageModalTitle"><i class="fas fa-pencil-alt me-2"></i>{{ t('ui.echomail.edit_message', {}, locale, ['common']) }}</h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body"> <table class="table table-sm table-borderless mb-3"> <tbody> <tr> <th class="text-muted small fw-normal ps-0" style="width:30%">{{ t('ui.common.db_id', {}, locale, ['common']) }}</th> <td class="small font-monospace" id="editMsgDbId"></td> </tr> <tr> <th class="text-muted small fw-normal ps-0">{{ t('ui.common.message_id', {}, locale, ['common']) }}</th> <td class="small font-monospace" id="editMsgId"></td> </tr> <tr> <th class="text-muted small fw-normal ps-0">{{ t('ui.common.date_label', {}, locale, ['common']) }}</th> <td class="small" id="editMsgDate"></td> </tr> <tr> <th class="text-muted small fw-normal ps-0">{{ t('ui.common.from_label', {}, locale, ['common']) }}</th> <td class="small" id="editMsgFrom"></td> </tr> <tr> <th class="text-muted small fw-normal ps-0">{{ t('ui.common.subject_label', {}, locale, ['common']) }}</th> <td class="small" id="editMsgSubject"></td> </tr> </tbody> </table> <hr> <div class="mb-3"> <label for="editArtFormat" class="form-label">{{ t('ui.echomail.art_format', {}, locale, ['common']) }}</label> <select class="form-select" id="editArtFormat"> <option value="">{{ t('ui.echomail.art_format_auto', {}, locale, ['common']) }}</option> <option value="plain">{{ t('ui.echomail.art_format_plain', {}, locale, ['common']) }}</option> <option value="ansi">{{ t('ui.echomail.art_format_ansi', {}, locale, ['common']) }}</option> <option value="amiga_ansi">{{ t('ui.echomail.art_format_amiga_ansi', {}, locale, ['common']) }}</option> </select> </div> <div class="mb-3"> <label for="editCharset" class="form-label">{{ t('ui.echomail.message_charset', {}, locale, ['common']) }}</label> <select class="form-select" id="editCharset"> {% for cs in supported_charsets %} <option value="{{ cs.value }}">{{ cs.label }}</option> {% endfor %} </select> </div> <div id="editMessageError" class="alert alert-danger d-none"></div> <div id="editMessageSuccess" class="alert alert-success d-none"> <i class="fas fa-check-circle me-2"></i>{{ t('ui.echomail.edit_message_saved', {}, locale, ['common']) }} </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ t('ui.common.close', {}, locale, ['common']) }}</button> <button type="button" class="btn btn-primary" id="saveEditMessageBtn" onclick="saveEditMessage()"> <i class="fas fa-save me-1"></i>{{ t('ui.common.save', {}, locale, ['common']) }} </button> </div> </div> </div> </div> {% if ai_assistant_enabled %} {% include 'partials/ai_assistant_modal.twig' %} {% endif %} {% endblock %} {% block scripts %} <script> window.systemAddress = '{{ system_address }}'; window.currentUser = {{ current_user|json_encode(15)|raw }}; </script> <script src="/js/ansisys.js"></script> <script src="/js/sixel.js"></script> <script src="/js/pcboard.js"></script> <script src="/js/message-list-context-menu.js"></script> <script src="/js/netmail.js"></script> <script src="/vendor/marked.min.js"></script> <script src="/js/ai-assistant.js?v=1"></script> <style> /* Read/Unread message styling - colors handled by theme stylesheets */ .message-row.table-light strong { font-weight: 600; } /* Threading styles */ .thread-root { border-left: 3px solid #0d6efd; background-color: rgba(13, 110, 253, 0.05); } .thread-level-1 { border-left: 2px solid #6c757d; background-color: rgba(108, 117, 125, 0.05); } .thread-level-2 { border-left: 2px solid #28a745; background-color: rgba(40, 167, 69, 0.05); } .thread-level-3 { border-left: 2px solid #ffc107; background-color: rgba(255, 193, 7, 0.05); } .thread-level-4, .thread-level-5, .thread-level-6, .thread-level-7, .thread-level-8, .thread-level-9 { border-left: 2px solid #dc3545; background-color: rgba(220, 53, 69, 0.05); } /* Thread root styling enhancement */ .thread-root .message-subject { font-weight: 500; } /* Reply badge styling */ .thread-root .badge.bg-secondary { background-color: #0d6efd !important; font-size: 0.7em; } /* Hover effects for threads */ .thread-root:hover { background-color: rgba(13, 110, 253, 0.1) !important; } .thread-reply:hover { background-color: rgba(108, 117, 125, 0.1) !important; } /* Threading icons */ .thread-reply .fa-reply { color: #6c757d; font-size: 0.8em; } /* Address Book Styling */ .address-book-entry { transition: all 0.2s ease; } .address-book-entry:hover { background-color: #f8f9fa; border-color: #0d6efd !important; transform: translateY(-1px); box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .address-book-entry .dropdown-toggle { opacity: 0.6; transition: opacity 0.2s ease; } .address-book-entry:hover .dropdown-toggle { opacity: 1; } .smaller { font-size: 0.75em; } /* Ensure proper spacing in threaded view */ .thread-reply td { vertical-align: middle; } /* Mobile threading adjustments */ @media (max-width: 991.98px) { .thread-level-1, .thread-level-2, .thread-level-3, .thread-level-4, .thread-level-5, .thread-level-6, .thread-level-7, .thread-level-8, .thread-level-9 { border-left-width: 1px; } .thread-root { border-left-width: 2px; } } /* Mobile filter controls */ @media (max-width: 575.98px) { /* Reduce thread indentation on very small screens */ td[style*="padding-left"] { padding-left: 5px !important; } /* Make filter controls full width and scrollable on mobile */ .filter-controls { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; padding-bottom: 2px; } .filter-controls .btn-group { flex-shrink: 0; } .filter-controls .btn { padding: 0.25rem 0.5rem; font-size: 0.75rem; } } /* Search term highlighting */ .search-highlight { background-color: #ffff00 !important; color: #000000 !important; font-weight: 600; padding: 0.1em 0.2em; border-radius: 0.2em; box-shadow: 0 0 0 1px #cccc00; } /* Ensure highlighting works in different contexts */ .message-formatted .search-highlight, .message-preformatted .search-highlight, .quote-line .search-highlight, .message-line .search-highlight, .message-signature .search-highlight { background-color: #ffff00 !important; color: #000000 !important; font-weight: 600; padding: 0.1em 0.2em; border-radius: 0.2em; box-shadow: 0 0 0 1px #cccc00; } /* Dark mode support for search highlighting */ @media (prefers-color-scheme: dark) { .search-highlight, .message-formatted .search-highlight, .message-preformatted .search-highlight, .quote-line .search-highlight, .message-line .search-highlight, .message-signature .search-highlight { background-color: #ffff66 !important; color: #000000 !important; box-shadow: 0 0 0 1px #cccc00; } } /* Modal header layout improvements */ .modal-header { display: flex; justify-content: space-between; align-items: center; } .modal-title { flex: 1; text-align: center; margin: 0 1rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Message modal navigation buttons */ .modal-header .btn-sm { padding: 0.25rem 0.5rem; font-size: 0.875rem; min-width: 32px; } .modal-header .btn-sm:disabled { opacity: 0.3; cursor: not-allowed; } .modal-header .btn-sm i { font-size: 0.75rem; } .modal-header .d-flex { flex-shrink: 0; } /* Mobile modal navigation adjustments */ @media (max-width: 576px) { .modal-header .btn-sm { padding: 0.2rem 0.4rem; font-size: 0.8rem; min-width: 28px; } .modal-header .btn-sm i { font-size: 0.7rem; } .modal-title { font-size: 1rem; margin: 0 0.5rem; } } </style> {% endblock %}