Spaces:
Running
Running
| <html lang="pt-BR"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Meu Armazenamento Pessoal</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary-color: #4a6fa5; | |
| --secondary-color: #166088; | |
| --accent-color: #4fc3f7; | |
| --light-color: #f8f9fa; | |
| --dark-color: #343a40; | |
| --success-color: #28a745; | |
| --danger-color: #dc3545; | |
| --warning-color: #ffc107; | |
| --border-radius: 8px; | |
| --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| --transition: all 0.3s ease; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| body { | |
| background-color: #f5f7fa; | |
| color: var(--dark-color); | |
| line-height: 1.6; | |
| padding: 20px; | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| header { | |
| background-color: var(--primary-color); | |
| color: white; | |
| padding: 1.5rem; | |
| border-radius: var(--border-radius); | |
| box-shadow: var(--box-shadow); | |
| margin-bottom: 2rem; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| gap: 1rem; | |
| } | |
| .logo { | |
| font-size: 1.8rem; | |
| font-weight: bold; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .logo i { | |
| font-size: 2rem; | |
| } | |
| .header-right { | |
| display: flex; | |
| align-items: center; | |
| gap: 1rem; | |
| flex-wrap: wrap; | |
| } | |
| .anycoder-link { | |
| color: white; | |
| text-decoration: none; | |
| font-size: 0.9rem; | |
| opacity: 0.8; | |
| transition: var(--transition); | |
| } | |
| .anycoder-link:hover { | |
| opacity: 1; | |
| text-decoration: underline; | |
| } | |
| .user-info { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| background-color: rgba(255, 255, 255, 0.1); | |
| padding: 0.5rem 1rem; | |
| border-radius: 20px; | |
| } | |
| .user-avatar { | |
| width: 30px; | |
| height: 30px; | |
| border-radius: 50%; | |
| background-color: var(--accent-color); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| font-weight: bold; | |
| } | |
| .main-container { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 2rem; | |
| flex: 1; | |
| } | |
| .stats-cards { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | |
| gap: 1.5rem; | |
| margin-bottom: 2rem; | |
| } | |
| .stat-card { | |
| background-color: white; | |
| border-radius: var(--border-radius); | |
| padding: 1.5rem; | |
| box-shadow: var(--box-shadow); | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.5rem; | |
| transition: var(--transition); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .stat-card::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 4px; | |
| background: linear-gradient(90deg, var(--accent-color), var(--primary-color)); | |
| } | |
| .stat-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15); | |
| } | |
| .stat-icon { | |
| width: 50px; | |
| height: 50px; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 1.5rem; | |
| color: white; | |
| } | |
| .stat-icon.notes { | |
| background-color: #66bb6a; | |
| } | |
| .stat-icon.contacts { | |
| background-color: #26c6da; | |
| } | |
| .stat-icon.passwords { | |
| background-color: #ffa726; | |
| } | |
| .stat-icon.others { | |
| background-color: #ab47bc; | |
| } | |
| .stat-value { | |
| font-size: 2rem; | |
| font-weight: bold; | |
| color: var(--secondary-color); | |
| } | |
| .stat-label { | |
| color: var(--dark-color); | |
| font-size: 0.9rem; | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| } | |
| .content-area { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 2rem; | |
| flex: 1; | |
| } | |
| .section { | |
| background-color: white; | |
| border-radius: var(--border-radius); | |
| padding: 2rem; | |
| box-shadow: var(--box-shadow); | |
| } | |
| .section-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 1.5rem; | |
| flex-wrap: wrap; | |
| gap: 1rem; | |
| } | |
| .section-title { | |
| font-size: 1.5rem; | |
| color: var(--secondary-color); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .section-actions { | |
| display: flex; | |
| gap: 0.5rem; | |
| } | |
| .btn { | |
| padding: 0.5rem 1rem; | |
| border: none; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-weight: 500; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .btn-primary { | |
| background-color: var(--primary-color); | |
| color: white; | |
| } | |
| .btn-primary:hover { | |
| background-color: var(--secondary-color); | |
| } | |
| .btn-secondary { | |
| background-color: var(--light-color); | |
| color: var(--dark-color); | |
| border: 1px solid #ddd; | |
| } | |
| .btn-secondary:hover { | |
| background-color: #e9ecef; | |
| } | |
| .btn-danger { | |
| background-color: var(--danger-color); | |
| color: white; | |
| } | |
| .btn-danger:hover { | |
| background-color: #c82333; | |
| } | |
| .btn-success { | |
| background-color: var(--success-color); | |
| color: white; | |
| } | |
| .btn-success:hover { | |
| background-color: #218838; | |
| } | |
| .search-container { | |
| margin-bottom: 1.5rem; | |
| position: relative; | |
| } | |
| .search-input { | |
| width: 100%; | |
| padding: 0.75rem 1rem; | |
| border: 1px solid #ddd; | |
| border-radius: var(--border-radius); | |
| font-size: 1rem; | |
| transition: var(--transition); | |
| padding-left: 2.5rem; | |
| } | |
| .search-input:focus { | |
| outline: none; | |
| border-color: var(--accent-color); | |
| box-shadow: 0 0 0 3px rgba(79, 195, 247, 0.2); | |
| } | |
| .search-icon { | |
| position: absolute; | |
| left: 10px; | |
| top: 50%; | |
| transform: translateY(-50%); | |
| color: #666; | |
| } | |
| .items-container { | |
| display: grid; | |
| gap: 1rem; | |
| } | |
| .item-card { | |
| border: 1px solid #eee; | |
| border-radius: var(--border-radius); | |
| padding: 1rem; | |
| transition: var(--transition); | |
| background-color: white; | |
| } | |
| .item-card:hover { | |
| border-color: var(--accent-color); | |
| box-shadow: 0 2px 8px rgba(79, 195, 247, 0.2); | |
| } | |
| .item-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 0.5rem; | |
| } | |
| .item-title { | |
| font-weight: bold; | |
| color: var(--secondary-color); | |
| font-size: 1.1rem; | |
| } | |
| .item-actions { | |
| display: flex; | |
| gap: 0.5rem; | |
| } | |
| .item-meta { | |
| display: flex; | |
| gap: 1rem; | |
| font-size: 0.8rem; | |
| color: #666; | |
| margin-bottom: 0.5rem; | |
| } | |
| .item-content { | |
| color: var(--dark-color); | |
| margin-top: 0.5rem; | |
| } | |
| .item-tag { | |
| display: inline-block; | |
| padding: 0.2rem 0.5rem; | |
| border-radius: 4px; | |
| font-size: 0.7rem; | |
| font-weight: bold; | |
| text-transform: uppercase; | |
| } | |
| .tag-notes { | |
| background-color: #e8f5e9; | |
| color: #2e7d32; | |
| } | |
| .tag-contacts { | |
| background-color: #e0f7fa; | |
| color: #006064; | |
| } | |
| .tag-passwords { | |
| background-color: #fff8e1; | |
| color: #e65100; | |
| } | |
| .tag-others { | |
| background-color: #f3e5f5; | |
| color: #4a148c; | |
| } | |
| .modal { | |
| display: none; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-color: rgba(0, 0, 0, 0.5); | |
| z-index: 1000; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| .modal.active { | |
| display: flex; | |
| } | |
| .modal-content { | |
| background-color: white; | |
| padding: 2rem; | |
| border-radius: var(--border-radius); | |
| width: 90%; | |
| max-width: 500px; | |
| max-height: 90vh; | |
| overflow-y: auto; | |
| box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); | |
| position: relative; | |
| } | |
| .modal-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 1.5rem; | |
| padding-bottom: 1rem; | |
| border-bottom: 1px solid #eee; | |
| } | |
| .modal-title { | |
| font-size: 1.5rem; | |
| color: var(--secondary-color); | |
| } | |
| .close-modal { | |
| background: none; | |
| border: none; | |
| font-size: 1.5rem; | |
| cursor: pointer; | |
| color: #666; | |
| transition: var(--transition); | |
| } | |
| .close-modal:hover { | |
| color: var(--danger-color); | |
| } | |
| .form-group { | |
| margin-bottom: 1.5rem; | |
| } | |
| .form-label { | |
| display: block; | |
| margin-bottom: 0.5rem; | |
| font-weight: 500; | |
| color: var(--dark-color); | |
| } | |
| .form-control { | |
| width: 100%; | |
| padding: 0.75rem; | |
| border: 1px solid #ddd; | |
| border-radius: var(--border-radius); | |
| font-size: 1rem; | |
| transition: var(--transition); | |
| } | |
| .form-control:focus { | |
| outline: none; | |
| border-color: var(--accent-color); | |
| box-shadow: 0 0 0 3px rgba(79, 195, 247, 0.2); | |
| } | |
| .form-select { | |
| appearance: none; | |
| background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); | |
| background-repeat: no-repeat; | |
| background-position: right 0.75rem center; | |
| background-size: 1em; | |
| padding-right: 2.5rem; | |
| } | |
| .textarea { | |
| min-height: 120px; | |
| resize: vertical; | |
| } | |
| .modal-footer { | |
| display: flex; | |
| justify-content: flex-end; | |
| gap: 0.5rem; | |
| margin-top: 1.5rem; | |
| padding-top: 1rem; | |
| border-top: 1px solid #eee; | |
| } | |
| .empty-state { | |
| text-align: center; | |
| padding: 2rem; | |
| color: #666; | |
| } | |
| .empty-state i { | |
| font-size: 3rem; | |
| margin-bottom: 1rem; | |
| color: #ddd; | |
| } | |
| .category-tabs { | |
| display: flex; | |
| gap: 0.5rem; | |
| margin-bottom: 1.5rem; | |
| border-bottom: 1px solid #eee; | |
| } | |
| .tab { | |
| padding: 0.5rem 1rem; | |
| cursor: pointer; | |
| border: none; | |
| background: none; | |
| color: #666; | |
| border-bottom: 2px solid transparent; | |
| transition: var(--transition); | |
| font-weight: 500; | |
| } | |
| .tab.active { | |
| color: var(--primary-color); | |
| border-bottom-color: var(--primary-color); | |
| } | |
| .tab:hover { | |
| color: var(--primary-color); | |
| } | |
| .password-field { | |
| position: relative; | |
| } | |
| .toggle-password { | |
| position: absolute; | |
| right: 10px; | |
| top: 50%; | |
| transform: translateY(-50%); | |
| background: none; | |
| border: none; | |
| color: #666; | |
| cursor: pointer; | |
| } | |
| .copy-btn { | |
| background: none; | |
| border: none; | |
| color: var(--primary-color); | |
| cursor: pointer; | |
| font-size: 0.9rem; | |
| margin-left: 0.5rem; | |
| } | |
| .toast { | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| background-color: white; | |
| padding: 1rem 1.5rem; | |
| border-radius: var(--border-radius); | |
| box-shadow: var(--box-shadow); | |
| display: flex; | |
| align-items: center; | |
| gap: 1rem; | |
| transform: translateX(100%); | |
| transition: var(--transition); | |
| z-index: 1001; | |
| } | |
| .toast.show { | |
| transform: translateX(0); | |
| } | |
| .toast.success { | |
| border-left: 4px solid var(--success-color); | |
| } | |
| .toast.error { | |
| border-left: 4px solid var(--danger-color); | |
| } | |
| .toast.info { | |
| border-left: 4px solid var(--accent-color); | |
| } | |
| @media (max-width: 768px) { | |
| header { | |
| flex-direction: column; | |
| align-items: flex-start; | |
| } | |
| .header-right { | |
| width: 100%; | |
| justify-content: space-between; | |
| } | |
| .section-header { | |
| flex-direction: column; | |
| align-items: flex-start; | |
| } | |
| .section-actions { | |
| width: 100%; | |
| justify-content: flex-end; | |
| } | |
| .modal-content { | |
| width: 95%; | |
| padding: 1.5rem; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| body { | |
| padding: 10px; | |
| } | |
| .stats-cards { | |
| grid-template-columns: 1fr; | |
| } | |
| .items-container { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="logo"> | |
| <i class="fas fa-lock"></i> | |
| <span>Meu Armazenamento</span> | |
| </div> | |
| <div class="header-right"> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" class="anycoder-link" target="_blank"> | |
| <i class="fas fa-code"></i> Built with anycoder | |
| </a> | |
| <div class="user-info"> | |
| <div class="user-avatar">U</div> | |
| <span>Usuário</span> | |
| </div> | |
| </div> | |
| </header> | |
| <div class="main-container"> | |
| <div class="stats-cards"> | |
| <div class="stat-card"> | |
| <div class="stat-icon notes"> | |
| <i class="fas fa-sticky-note"></i> | |
| </div> | |
| <div class="stat-value" id="notes-count">0</div> | |
| <div class="stat-label">Notas</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-icon contacts"> | |
| <i class="fas fa-address-book"></i> | |
| </div> | |
| <div class="stat-value" id="contacts-count">0</div> | |
| <div class="stat-label">Contatos</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-icon passwords"> | |
| <i class="fas fa-key"></i> | |
| </div> | |
| <div class="stat-value" id="passwords-count">0</div> | |
| <div class="stat-label">Senhas</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="stat-icon others"> | |
| <i class="fas fa-box-open"></i> | |
| </div> | |
| <div class="stat-value" id="others-count">0</div> | |
| <div class="stat-label">Outros</div> | |
| </div> | |
| </div> | |
| <div class="content-area"> | |
| <div class="section"> | |
| <div class="section-header"> | |
| <h2 class="section-title"> | |
| <i class="fas fa-folder-open"></i> | |
| <span>Meus Itens</span> | |
| </h2> | |
| <div class="section-actions"> | |
| <button class="btn btn-secondary" id="export-btn"> | |
| <i class="fas fa-download"></i> Exportar | |
| </button> | |
| <button class="btn btn-primary" id="add-btn"> | |
| <i class="fas fa-plus"></i> Adicionar Item | |
| </button> | |
| </div> | |
| </div> | |
| <div class="category-tabs"> | |
| <button class="tab active" data-category="all"> | |
| <i class="fas fa-th-large"></i> Todos | |
| </button> | |
| <button class="tab" data-category="notes"> | |
| <i class="fas fa-sticky-note"></i> Notas | |
| </button> | |
| <button class="tab" data-category="contacts"> | |
| <i class="fas fa-address-book"></i> Contatos | |
| </button> | |
| <button class="tab" data-category="passwords"> | |
| <i class="fas fa-key"></i> Senhas | |
| </button> | |
| <button class="tab" data-category="others"> | |
| <i class="fas fa-box-open"></i> Outros | |
| </button> | |
| </div> | |
| <div class="search-container"> | |
| <i class="fas fa-search search-icon"></i> | |
| <input type="text" class="search-input" id="search-input" placeholder="Pesquisar itens..."> | |
| </div> | |
| <div class="items-container" id="items-container"> | |
| <div class="empty-state"> | |
| <i class="fas fa-inbox"></i> | |
| <p>Nenhum item encontrado. Clique em "Adicionar Item" para começar.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Modal para adicionar/editar item --> | |
| <div class="modal" id="item-modal"> | |
| <div class="modal-content"> | |
| <div class="modal-header"> | |
| <h3 class="modal-title" id="modal-title">Adicionar Item</h3> | |
| <button class="close-modal" id="close-modal"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <form id="item-form"> | |
| <input type="hidden" id="item-id"> | |
| <div class="form-group"> | |
| <label for="item-title" class="form-label">Título</label> | |
| <input type="text" class="form-control" id="item-title" required> | |
| </div> | |
| <div class="form-group"> | |
| <label for="item-category" class="form-label">Categoria</label> | |
| <select class="form-control form-select" id="item-category" required> | |
| <option value="notes">Notas</option> | |
| <option value="contacts">Contatos</option> | |
| <option value="passwords">Senhas</option> | |
| <option value="others">Outros</option> | |
| </select> | |
| </div> | |
| <div class="form-group" id="password-fields" style="display: none;"> | |
| <label for="item-username" class="form-label">Usuário</label> | |
| <input type="text" class="form-control" id="item-username"> | |
| </div> | |
| <div class="form-group" id="password-field" style="display: none;"> | |
| <label for="item-password" class="form-label">Senha</label> | |
| <div class="password-field"> | |
| <input type="password" class="form-control" id="item-password"> | |
| <button type="button" class="toggle-password" id="toggle-password"> | |
| <i class="fas fa-eye"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="form-group" id="contact-fields" style="display: none;"> | |
| <label for="item-email" class="form-label">Email</label> | |
| <input type="email" class="form-control" id="item-email"> | |
| </div> | |
| <div class="form-group" id="contact-phone-field" style="display: none;"> | |
| <label for="item-phone" class="form-label">Telefone</label> | |
| <input type="tel" class="form-control" id="item-phone"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="item-content" class="form-label">Conteúdo</label> | |
| <textarea class="form-control textarea" id="item-content"></textarea> | |
| </div> | |
| <div class="form-group"> | |
| <label for="item-tags" class="form-label">Tags (separadas por vírgula)</label> | |
| <input type="text" class="form-control" id="item-tags"> | |
| </div> | |
| <div class="modal-footer"> | |
| <button type="button" class="btn btn-secondary" id="cancel-btn">Cancelar</button> | |
| <button type="submit" class="btn btn-primary" id="save-btn">Salvar</button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| <!-- Toast notification --> | |
| <div class="toast" id="toast"> | |
| <i class="fas fa-check-circle" id="toast-icon"></i> | |
| <span id="toast-message"></span> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Elements | |
| const addBtn = document.getElementById('add-btn'); | |
| const modal = document.getElementById('item-modal'); | |
| const closeModal = document.getElementById('close-modal'); | |
| const cancelBtn = document.getElementById('cancel-btn'); | |
| const itemForm = document.getElementById('item-form'); | |
| const modalTitle = document.getElementById('modal-title'); | |
| const itemId = document.getElementById('item-id'); | |
| const itemTitle = document.getElementById('item-title'); | |
| const itemCategory = document.getElementById('item-category'); | |
| const itemContent = document.getElementById('item-content'); | |
| const itemTags = document.getElementById('item-tags'); | |
| const itemsContainer = document.getElementById('items-container'); | |
| const searchInput = document.getElementById('search-input'); | |
| const categoryTabs = document.querySelectorAll('.tab'); | |
| const exportBtn = document.getElementById('export-btn'); | |
| const toast = document.getElementById('toast'); | |
| const toastMessage = document.getElementById('toast-message'); | |
| const toastIcon = document.getElementById('toast-icon'); | |
| // Password fields | |
| const passwordFields = document.getElementById('password-fields'); | |
| const passwordField = document.getElementById('password-field'); | |
| const togglePassword = document.getElementById('toggle-password'); | |
| const itemPassword = document.getElementById('item-password'); | |
| // Contact fields | |
| const contactFields = document.getElementById('contact-fields'); | |
| const contactPhoneField = document.getElementById('contact-phone-field'); | |
| const itemEmail = document.getElementById('item-email'); | |
| const itemPhone = document.getElementById('item-phone'); | |
| const itemUsername = document.getElementById('item-username'); | |
| // Stats elements | |
| const notesCount = document.getElementById('notes-count'); | |
| const contactsCount = document.getElementById('contacts-count'); | |
| const passwordsCount = document.getElementById('passwords-count'); | |
| const othersCount = document.getElementById('others-count'); | |
| let currentItems = []; | |
| let currentCategory = 'all'; | |
| let editingId = null; | |
| // Initialize the app | |
| init(); | |
| function init() { | |
| // Load items from localStorage | |
| loadItems(); | |
| // Set up event listeners | |
| addBtn.addEventListener('click', openAddModal); | |
| closeModal.addEventListener('click', closeModalHandler); | |
| cancelBtn.addEventListener('click', closeModalHandler); | |
| itemForm.addEventListener('submit', saveItem); | |
| searchInput.addEventListener('input', filterItems); | |
| exportBtn.addEventListener('click', exportData); | |
| // Category tabs | |
| categoryTabs.forEach(tab => { | |
| tab.addEventListener('click', () => { | |
| categoryTabs.forEach(t => t.classList.remove('active')); | |
| tab.classList.add('active'); | |
| currentCategory = tab.dataset.category; | |
| filterItems(); | |
| }); | |
| }); | |
| // Item category change | |
| itemCategory.addEventListener('change', toggleCategoryFields); | |
| // Toggle password visibility | |
| togglePassword.addEventListener('click', () => { | |
| const type = itemPassword.getAttribute('type') === 'password' ? 'text' : 'password'; | |
| itemPassword.setAttribute('type', type); | |
| togglePassword.innerHTML = type === 'password' ? | |
| '<i class="fas fa-eye"></i>' : | |
| '<i class="fas fa-eye-slash"></i>'; | |
| }); | |
| // Update stats | |
| updateStats(); | |
| } | |
| function loadItems() { | |
| const items = localStorage.getItem('personalStorageItems'); | |
| currentItems = items ? JSON.parse(items) : []; | |
| renderItems(); | |
| } | |
| function saveItems() { | |
| localStorage.setItem('personalStorageItems', JSON.stringify(currentItems)); | |
| updateStats(); | |
| } | |
| function renderItems() { | |
| if (currentItems.length === 0) { | |
| itemsContainer.innerHTML = ` | |
| <div class="empty-state"> | |
| <i class="fas fa-inbox"></i> | |
| <p>Nenhum item encontrado. Clique em "Adicionar Item" para começar.</p> | |
| </div> | |
| `; | |
| return; | |
| } | |
| let filteredItems = filterItemsByCategory(currentItems, currentCategory); | |
| if (searchInput.value) { | |
| const searchTerm = searchInput.value.toLowerCase(); | |
| filteredItems = filteredItems.filter(item => | |
| item.title.toLowerCase().includes(searchTerm) || | |
| item.content.toLowerCase().includes(searchTerm) || | |
| (item.tags && item.tags.some(tag => tag.toLowerCase().includes(searchTerm))) | |
| ); | |
| } | |
| if (filteredItems.length === 0) { | |
| itemsContainer.innerHTML = ` | |
| <div class="empty-state"> | |
| <i class="fas fa-search"></i> | |
| <p>Nenhum item corresponde à sua pesquisa.</p> | |
| </div> | |
| `; | |
| return; | |
| } | |
| itemsContainer.innerHTML = filteredItems.map(item => ` | |
| <div class="item-card" data-id="${item.id}"> | |
| <div class="item-header"> | |
| <div class="item-title">${item.title}</div> | |
| <div class="item-actions"> | |
| <button class="btn btn-secondary copy-btn" title="Copiar" onclick="copyItemContent('${item.id}')"> | |
| <i class="fas fa-copy"></i> | |
| </button> | |
| <button class="btn btn-secondary" title="Editar" onclick="editItem('${item.id}')"> | |
| <i class="fas fa-edit"></i> | |
| </button> | |
| <button class="btn btn-danger" title="Excluir" onclick="deleteItem('${item.id}')"> | |
| <i class="fas fa-trash"></i> | |
| </button> | |
| </div> | |
| </div> | |
| ${item.category === 'contacts' && item.email ? | |
| `<div class="item-meta"> | |
| <span><i class="fas fa-envelope"></i> ${item.email}</span> | |
| ${item.phone ? `<span><i class="fas fa-phone"></i> ${item.phone}</span>` : ''} | |
| </div>` : ''} | |
| ${item.category === 'passwords' && item.username ? | |
| `<div class="item-meta"> | |
| <span><i class="fas fa-user"></i> ${item.username}</span> | |
| <span> | |
| <i class="fas fa-lock"></i> •••••••• | |
| <button class="copy-btn" title="Copiar senha" onclick="copyPassword('${item.id}')"> | |
| <i class="fas fa-copy"></i> | |
| </button> | |
| </span> | |
| </div>` : ''} | |
| <div class="item-content">${item.content}</div> | |
| ${item.tags && item.tags.length > 0 ? | |
| `<div class="item-meta" style="margin-top: 0.5rem;"> | |
| ${item.tags.map(tag => `<span class="item-tag tag-${item.category}">${tag}</span>`).join('')} | |
| </div>` : ''} | |
| <div class="item-meta" style="margin-top: 0.5rem;"> | |
| <span><i class="fas fa-calendar"></i> ${new Date(item.createdAt).toLocaleDateString()}</span> | |
| <span class="item-tag tag-${item.category}">${getCategoryLabel(item.category)}</span> | |
| </div> | |
| </div> | |
| `).join(''); | |
| } | |
| function filterItemsByCategory(items, category) { | |
| if (category === 'all') return items; | |
| return items.filter(item => item.category === category); | |
| } | |
| function filterItems() { | |
| renderItems(); | |
| } | |
| function openAddModal() { | |
| editingId = null; | |
| modalTitle.textContent = 'Adicionar Item'; | |
| itemForm.reset(); | |
| toggleCategoryFields(); | |
| modal.classList.add('active'); | |
| itemTitle.focus(); | |
| } | |
| function editItem(id) { | |
| const item = currentItems.find(item => item.id === id); | |
| if (!item) return; | |
| editingId = id; | |
| modalTitle.textContent = 'Editar Item'; | |
| itemId.value = item.id; | |
| itemTitle.value = item.title; | |
| itemCategory.value = item.category; | |
| itemContent.value = item.content || ''; | |
| itemTags.value = item.tags ? item.tags.join(', ') : ''; | |
| // Set category-specific fields | |
| if (item.category === 'passwords') { | |
| itemUsername.value = item.username || ''; | |
| itemPassword.value = item.password || ''; | |
| } else if (item.category === 'contacts') { | |
| itemEmail.value = item.email || ''; | |
| itemPhone.value = item.phone || ''; | |
| } | |
| toggleCategoryFields(); | |
| modal.classList.add('active'); | |
| } | |
| function closeModalHandler() { | |
| modal.classList.remove('active'); | |
| editingId = null; | |
| } | |
| function saveItem(e) { | |
| e.preventDefault(); | |
| const newItem = { | |
| id: editingId || Date.now().toString(), | |
| title: itemTitle.value.trim(), | |
| category: itemCategory.value, | |
| content: itemContent.value.trim(), | |
| tags: itemTags.value.trim() ? itemTags.value.split(',').map(tag => tag.trim()) : [], | |
| createdAt: editingId ? currentItems.find(item => item.id === editingId).createdAt : new Date().toISOString() | |
| }; | |
| // Add category-specific fields | |
| if (newItem.category === 'passwords') { | |
| newItem.username = itemUsername.value.trim(); | |
| newItem.password = itemPassword.value; | |
| } else if (newItem.category === 'contacts') { | |
| newItem.email = itemEmail.value.trim(); | |
| newItem.phone = itemPhone.value.trim(); | |
| } | |
| if (editingId) { | |
| // Update existing item | |
| const index = currentItems.findIndex(item => item.id === editingId); | |
| currentItems[index] = newItem; | |
| showToast('Item atualizado com sucesso!', 'success'); | |
| } else { | |
| // Add new item | |
| currentItems.push(newItem); | |
| showToast('Item adicionado com sucesso!', 'success'); | |
| } | |
| saveItems(); | |
| renderItems(); | |
| closeModalHandler(); | |
| } | |
| function deleteItem(id) { | |
| if (confirm('Tem certeza que deseja excluir este item?')) { | |
| currentItems = currentItems.filter(item => item.id !== id); | |
| saveItems(); | |
| renderItems(); | |
| showToast('Item excluído com sucesso!', 'info'); | |
| } | |
| } | |
| function toggleCategoryFields() { | |
| const category = itemCategory.value; | |
| // Hide all category-specific fields | |
| passwordFields.style.display = 'none'; | |
| passwordField.style.display = 'none'; | |
| contactFields.style.display = 'none'; | |
| contactPhoneField.style.display = 'none'; | |
| // Show fields based on category | |
| if (category === 'passwords') { | |
| passwordFields.style.display = 'block'; | |
| passwordField.style.display = 'block'; | |
| } else if (category === 'contacts') { | |
| contactFields.style.display = 'block'; | |
| contactPhoneField.style.display = 'block'; | |
| } | |
| } | |
| function getCategoryLabel(category) { | |
| const labels = { | |
| notes: 'Notas', | |
| contacts: 'Contatos', | |
| passwords: 'Senhas', | |
| others: 'Outros' | |
| }; | |
| return labels[category] || 'Outros'; | |
| } | |
| function updateStats() { | |
| const notes = currentItems.filter(item => item.category === 'notes').length; | |
| const contacts = currentItems.filter(item => item.category === 'contacts').length; | |
| const passwords = currentItems.filter(item => item.category === 'passwords').length; | |
| const others = currentItems.filter(item => item.category === 'others').length; | |
| notesCount.textContent = notes; | |
| contactsCount.textContent = contacts; | |
| passwordsCount.textContent = passwords; | |
| othersCount.textContent = others; | |
| } | |
| function exportData() { | |
| if (currentItems.length === 0) { | |
| showToast('Nenhum item para exportar!', 'warning'); | |
| return; | |
| } | |
| const data = JSON.stringify(currentItems, null, 2); | |
| const blob = new Blob([data], { type: 'application/json' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = `meu_armazenamento_${new Date().toISOString().split('T')[0]}.json`; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| showToast('Dados exportados com sucesso!', 'success'); | |
| } | |
| function copyItemContent(id) { | |
| const item = currentItems.find(item => item.id === id); | |
| if (item) { | |
| navigator.clipboard.writeText(item.content) | |
| .then(() => showToast('Conteúdo copiado para a área de transferência!', 'success')) | |
| .catch(() => showToast('Não foi possível copiar o conteúdo', 'error')); | |
| } | |
| } | |
| function copyPassword(id) { | |
| const item = currentItems.find(item => item.id === id); | |
| if (item && item.password) { | |
| navigator.clipboard.writeText(item.password) | |
| .then(() => showToast('Senha copiada para a área de transferência!', 'success')) | |
| .catch(() => showToast('Não foi possível copiar a senha', 'error')); | |
| } | |
| } | |
| function showToast(message, type = 'info') { | |
| toastMessage.textContent = message; | |
| // Set toast type | |
| toast.classList.remove('success', 'error', 'info', 'warning'); | |
| toast.classList.add(type); | |
| // Set icon based on type | |
| const icons = { | |
| success: 'fas fa-check-circle', | |
| error: 'fas fa-exclamation-circle', | |
| info: 'fas fa-info-circle', | |
| warning: 'fas fa-exclamation-triangle' | |
| }; | |
| toastIcon.className = icons[type] || 'fas fa-info-circle'; | |
| // Show toast | |
| toast.classList.add('show'); | |
| // Hide after 3 seconds | |
| setTimeout(() => { | |
| toast.classList.remove('show'); | |
| }, 3000); | |
| } | |
| // Make functions available globally for button onclick handlers | |
| window.editItem = editItem; | |
| window.deleteItem = deleteItem; | |
| window.copyItemContent = copyItemContent; | |
| window.copyPassword = copyPassword; | |
| }); | |
| </script> | |
| </body> | |
| </html> |