Чаты
Пользователи
Выберите чат
-Начните общение в одном из существующих чатов или создайте свой собственный.
-Выберите чат
+Начните общение в одном из существующих чатов или создайте свой собственный.
+diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -19,8 +19,12 @@ def init_db(): }, f, indent=4) def read_db(): - with open(DB_FILE, 'r') as f: - return json.load(f) + try: + with open(DB_FILE, 'r') as f: + return json.load(f) + except FileNotFoundError: + init_db() + return read_db() def write_db(data): with open(DB_FILE, 'w') as f: @@ -55,7 +59,9 @@ def index(): --success-color: #28a745; --error-color: #dc3545; --font-family: 'Inter', sans-serif; - --nav-height: 56px; + --border-radius-small: 6px; + --border-radius-medium: 12px; + --border-radius-large: 18px; } * { @@ -79,6 +85,7 @@ def index(): display: flex; align-items: center; justify-content: center; + position: relative; } .main-container { @@ -87,7 +94,7 @@ def index(): display: flex; flex-direction: column; transition: opacity 0.3s ease; - position: relative; /* Needed for absolute positioned elements inside */ + position: relative; } #login-view { @@ -121,46 +128,54 @@ def index(): } #app-view { - display: none; /* Managed by JS */ + display: none; width: 100%; height: 100%; - flex-direction: column; /* Default mobile layout */ + flex-direction: column; } - .app-main-content { + .content-area { flex-grow: 1; - overflow: hidden; /* Prevents children from overflowing */ - display: flex; /* For desktop side-by-side */ + overflow: hidden; + display: flex; + position: relative; + padding-bottom: 60px; /* Space for the bottom navigation */ } - #chatroom-list-view, - #user-list-view, - #chat-window-view { - width: 100%; /* Default mobile */ + .view { + width: 100%; height: 100%; - display: none; /* Managed by JS */ + flex-shrink: 0; + overflow-y: auto; + display: none; flex-direction: column; - background-color: var(--bg-secondary); } - - .view-header { + + #chats-view .list-header, + #users-view .list-header { padding: 16px; border-bottom: 1px solid var(--border-color); flex-shrink: 0; + background-color: var(--bg-secondary); /* Match nav background */ + } + + #chats-view .list-header-top, + #users-view .list-header-top { display: flex; justify-content: space-between; align-items: center; + margin-bottom: 16px; } - .view-header h2 { - font-size: 1.5rem; + #chats-view .list-header h2, + #users-view .list-header h2 { + font-size: 1.5rem; font-weight: 600; } - .list-view-actions { display: flex; align-items: center; gap: 8px; } - - .user-profile-section { + + .user-profile { padding: 12px; background-color: var(--bg-tertiary); - border-radius: 8px; + border-radius: var(--border-radius-small); margin-bottom: 16px; } #user-wallet, #user-nickname { @@ -176,7 +191,7 @@ def index(): background-color: var(--bg-primary); border: 1px solid var(--border-color); color: var(--text-primary); - border-radius: 6px; + border-radius: var(--border-radius-small); padding: 8px 12px; font-size: 0.9rem; } @@ -187,7 +202,7 @@ def index(): color: white; border: none; padding: 10px 16px; - border-radius: 6px; + border-radius: var(--border-radius-small); cursor: pointer; font-weight: 500; transition: transform 0.2s ease, box-shadow 0.2s ease; @@ -195,12 +210,9 @@ def index(): align-items: center; justify-content: center; gap: 8px; + flex-shrink: 0; } - .action-btn:disabled { - opacity: 0.6; - cursor: not-allowed; - } - .action-btn:not(:disabled):hover { + .action-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 15px rgba(0, 136, 204, 0.3); } @@ -212,9 +224,7 @@ def index(): .list-container { flex-grow: 1; overflow-y: auto; - padding-bottom: var(--nav-height); /* Space for mobile nav */ } - .list-item { display: flex; align-items: center; @@ -236,9 +246,16 @@ def index(): font-weight: 600; color: white; flex-shrink: 0; - text-transform: uppercase; - font-size: 1.2rem; + font-size: 1.1rem; } + + .avatar.small { + width: 36px; + height: 36px; + font-size: 1rem; + align-self: flex-end; + } + .item-info { flex-grow: 1; overflow: hidden; @@ -249,13 +266,13 @@ def index(): overflow: hidden; text-overflow: ellipsis; } - .item-secondary-text { - font-size: 0.9rem; - color: var(--text-secondary); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } + .item-description { + font-size: 0.9rem; + color: var(--text-secondary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } .lock-icon { width: 16px; @@ -264,8 +281,15 @@ def index(): flex-shrink: 0; } - #chat-window-view .view-header { - background-color: var(--bg-secondary); /* Ensure header contrast */ + #chat-window-view { + display: none; + flex-direction: column; + width: 100%; + height: 100%; + background-color: var(--bg-primary); + position: absolute; /* Position absolute for mobile overlay */ + top: 0; left: 0; + z-index: 10; /* Bring to front on mobile */ } .chat-header { @@ -281,8 +305,7 @@ def index(): background: none; border: none; cursor: pointer; - padding: 0; - display: none; /* Managed by JS */ + display: none; /* Hidden by default, shown on mobile */ } .back-btn svg { width: 24px; @@ -309,10 +332,10 @@ def index(): max-width: 80%; } .message .avatar { - width: 36px; - height: 36px; - align-self: flex-end; - font-size: 1rem; + width: 36px; + height: 36px; + font-size: 1rem; + align-self: flex-end; } .message-content { display: flex; @@ -328,10 +351,10 @@ def index(): } .message-bubble { padding: 10px 14px; - border-radius: 18px; + border-radius: var(--border-radius-large); line-height: 1.4; word-wrap: break-word; - white-space: pre-wrap; /* Preserve line breaks */ + box-shadow: 0 1px 3px rgba(0,0,0,0.1); } .message.sent { align-self: flex-end; flex-direction: row-reverse; } @@ -339,13 +362,14 @@ def index(): .message.sent .message-bubble { background: linear-gradient(45deg, var(--accent-blue), var(--accent-blue-light)); color: white; - border-bottom-right-radius: 4px; + border-bottom-right-radius: var(--border-radius-small); } .message.received { align-self: flex-start; } .message.received .message-bubble { background-color: var(--bg-tertiary); - border-bottom-left-radius: 4px; + color: var(--text-primary); + border-bottom-left-radius: var(--border-radius-small); } .chat-placeholder { @@ -358,11 +382,11 @@ def index(): color: var(--text-secondary); padding: 20px; } - .chat-placeholder img { width: 80px; margin-bottom: 20px; opacity: 0.5; } + .chat-placeholder img { width: 80px; margin-bottom: 20px; opacity: 0.3; } .message-form { display: flex; - padding: 16px; + padding: 12px 16px; gap: 12px; background-color: var(--bg-secondary); border-top: 1px solid var(--border-color); @@ -387,9 +411,81 @@ def index(): border-radius: 50%; flex-shrink: 0; padding: 0; + background: var(--accent-blue); + display: flex; + align-items: center; + justify-content: center; } .send-btn svg { width: 20px; height: 20px; fill: white; } + /* Bottom Navigation */ + .bottom-nav { + position: fixed; + bottom: 0; + left: 0; + width: 100%; + height: 60px; + background-color: rgba(24, 25, 28, 0.8); /* Semi-transparent */ + backdrop-filter: blur(10px); + border-top: 1px solid var(--border-color); + display: flex; + justify-content: space-around; + align-items: center; + z-index: 500; /* Below modals, above content */ + } + + .nav-item { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + flex-grow: 1; + cursor: pointer; + color: var(--text-secondary); + font-size: 0.75rem; + gap: 4px; + transition: color 0.2s ease; + } + + .nav-item svg { + width: 24px; + height: 24px; + fill: var(--text-secondary); + transition: fill 0.2s ease; + } + + .nav-item.active { + color: var(--accent-blue-light); + } + .nav-item.active svg { + fill: var(--accent-blue-light); + } + + .nav-item.qr-scanner-btn { + position: relative; + top: -15px; /* Visually lift the button */ + width: 56px; + height: 56px; + border-radius: 50%; + background: linear-gradient(45deg, var(--accent-blue-light), var(--accent-blue)); + color: white; + box-shadow: 0 4px 15px rgba(0, 136, 204, 0.4); + flex-shrink: 0; + font-size: 0; /* Hide text */ + transition: transform 0.2s ease, box-shadow 0.2s ease; + } + .nav-item.qr-scanner-btn svg { + fill: white; + width: 28px; + height: 28px; + } + .nav-item.qr-scanner-btn:hover { + transform: translateY(-17px); + box-shadow: 0 6px 20px rgba(0, 136, 204, 0.5); + } + + + /* Modals */ .modal-overlay { position: fixed; top: 0; @@ -401,195 +497,144 @@ def index(): align-items: center; justify-content: center; z-index: 1000; - -webkit-backdrop-filter: blur(5px); - backdrop-filter: blur(5px); - overflow-y: auto; /* Allow scrolling for tall modals */ + backdrop-filter: blur(10px); } .modal-content { background-color: var(--bg-secondary); padding: 24px; - border-radius: 12px; + border-radius: var(--border-radius-medium); width: 90%; max-width: 400px; border: 1px solid var(--border-color); box-shadow: 0 10px 30px rgba(0,0,0,0.5); - max-height: 90vh; /* Limit modal height */ - overflow-y: auto; /* Allow content scrolling */ } .modal-content h3 { margin-bottom: 20px; font-weight: 600; font-size: 1.3rem; } .modal-content label { display: block; margin-bottom: 8px; font-size: 0.9rem; color: var(--text-secondary); } - .modal-content input[type="text"], - .modal-content input[type="password"] { + .modal-content input { width: 100%; padding: 12px; margin-bottom: 16px; background-color: var(--bg-tertiary); border: 1px solid var(--border-color); - color: white; - border-radius: 6px; + color: var(--text-primary); + border-radius: var(--border-radius-small); font-size: 1rem; + outline: none; } + .modal-content input:focus { border-color: var(--accent-blue); } + .modal-actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 8px; } .modal-btn { padding: 10px 20px; - border-radius: 6px; + border-radius: var(--border-radius-small); border: none; cursor: pointer; font-weight: 500; + transition: opacity 0.2s ease; } + .modal-btn:hover { opacity: 0.9; } .secondary-btn { background-color: var(--bg-hover); color: white; } + .secondary-btn:hover { background-color: #3a3d43; } #profile-modal .modal-content { text-align: center; } #profile-avatar-container { margin: 20px auto; display: inline-block; } - #profile-avatar-container .avatar { width: 60px; height: 60px; font-size: 1.8rem; } - #profile-username { font-size: 1.2rem; font-weight: 600; word-break: break-word;} + #profile-username { font-size: 1.2rem; font-weight: 600; margin-bottom: 4px;} #profile-address { color: var(--text-secondary); font-size: 0.9rem; word-break: break-all; margin-top: 8px;} - #profile-balance { font-size: 1rem; margin-top: 8px; font-weight: 500;} - #profile-qr-code { background: white; padding: 10px; margin: 20px auto; width: fit-content; border-radius: 8px; } - #profile-qr-code canvas, #profile-qr-code img { display: block; } /* Fix for QRCode.js margin */ - #profile-modal .modal-actions { flex-direction: column; gap: 12px; align-items: stretch; margin-top: 20px; } + #profile-qr-code { background: white; padding: 10px; margin: 20px auto; width: fit-content; border-radius: var(--border-radius-small);} + #profile-modal p:last-of-type { text-align: center; color: var(--text-secondary); font-size: 0.8rem; margin-top: -10px; margin-bottom: 20px;} + #profile-modal .modal-actions { flex-direction: column; gap: 12px; align-items: stretch;} - #scanner-modal .modal-content { - max-width: 450px; - } - #qr-reader { + + #scanner-modal #qr-reader { width: 100%; - aspect-ratio: 1 / 1; /* Keep square aspect ratio */ - max-width: 400px; /* Limit width */ - margin: 16px auto 0 auto; border: 1px solid var(--border-color); - border-radius: 8px; + margin-top: 16px; + border-radius: var(--border-radius-small); overflow: hidden; + aspect-ratio: 1 / 1; /* Keep scanner square */ } - #qr-reader__dashboard_section_swaplink { - display: none; /* Hide camera swap button */ - } - + /* Status Bar */ #status-bar { position: fixed; - bottom: calc(var(--nav-height) + 10px); /* Position above nav on mobile */ + bottom: 80px; /* Above nav */ left: 50%; transform: translateX(-50%); background-color: var(--bg-tertiary); color: white; padding: 12px 20px; - border-radius: 8px; + border-radius: var(--border-radius-small); font-size: 0.9rem; opacity: 0; visibility: hidden; - transition: opacity 0.3s ease, visibility 0.3s ease, bottom 0.3s ease; + transition: opacity 0.3s, visibility 0.3s; z-index: 2000; box-shadow: 0 5px 15px rgba(0,0,0,0.3); - max-width: 90%; - text-align: center; - word-break: break-word; } #status-bar.success { background-color: var(--success-color); } #status-bar.error { background-color: var(--error-color); } #status-bar.visible { opacity: 1; visibility: visible; } - #bottom-nav { - display: flex; - position: fixed; - bottom: 0; - left: 0; - width: 100%; - height: var(--nav-height); - background-color: var(--bg-secondary); - border-top: 1px solid var(--border-color); - z-index: 500; - justify-content: space-around; - align-items: center; - } - .nav-item { - flex-grow: 1; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - color: var(--text-secondary); - font-size: 0.75rem; - cursor: pointer; - transition: color 0.2s ease; - } - .nav-item.active { color: var(--accent-blue-light); } - .nav-item svg { - width: 24px; - height: 24px; - fill: var(--text-secondary); - margin-bottom: 4px; - transition: fill 0.2s ease; - } - .nav-item.active svg { fill: var(--accent-blue-light); } - /* Desktop Layout */ @media (min-width: 768px) { - body { align-items: center; justify-content: center; padding: 20px; } + body { + background-color: var(--bg-secondary); /* Slightly different background on desktop */ + } .main-container { - width: 100%; max-width: 1100px; - height: 100%; max-height: 800px; - border-radius: 12px; + border-radius: var(--border-radius-medium); overflow: hidden; box-shadow: 0 10px 40px rgba(0,0,0,0.3); border: 1px solid var(--border-color); - flex-direction: row; /* Desktop layout */ + flex-direction: row; /* Side by side layout */ } + #login-view { + border-radius: var(--border-radius-medium); + } #app-view { - display: flex; - flex-direction: row; /* Override mobile */ + flex-direction: row; } - .app-main-content { flex-direction: row; } + .content-area { + padding-bottom: 0; /* No space needed for bottom nav */ + position: static; + flex-direction: row; + } - #chatroom-list-view, - #user-list-view { - width: 320px; + .view { + width: 320px; /* Sidebar width */ flex-shrink: 0; + position: static; + z-index: auto; + display: flex !important; /* Always display list/users view pane */ border-right: 1px solid var(--border-color); - display: flex !important; /* Always flex on desktop */ - padding-bottom: 0; /* No space for nav */ } + #chats-view, #users-view { + width: 320px; + flex-direction: column; + } + #chat-window-view { width: auto; flex-grow: 1; - display: flex !important; /* Always flex on desktop */ + position: static; + z-index: auto; + display: flex !important; /* Always display chat window pane */ } - .list-container { padding-bottom: 0; } /* No space for nav */ - - .back-btn { display: none !important; } /* Hide back button on desktop */ + .bottom-nav { + display: none; /* Hide bottom nav on desktop */ + } - #bottom-nav { display: none; } /* Hide nav on desktop */ - #status-bar { bottom: 20px; } /* Lower status bar */ + .back-btn { + display: none !important; /* Hide back button on desktop */ + } - .view-header-tabs { - display: flex; - gap: 16px; - font-size: 1.1rem; - font-weight: 500; - color: var(--text-secondary); - } - .view-header-tab { - cursor: pointer; - position: relative; - padding-bottom: 8px; - } - .view-header-tab.active { - color: var(--text-primary); - } - .view-header-tab.active::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 2px; - background-color: var(--accent-blue); + #status-bar { + bottom: 20px; /* Move status bar back down */ } } @@ -604,85 +649,82 @@ def index():
Начните общение в одном из существующих чатов или создайте свой собственный.
-Начните общение в одном из существующих чатов или создайте свой собственный.
+