diff --git "a/app.py" "b/app.py"
--- "a/app.py"
+++ "b/app.py"
@@ -22,9 +22,15 @@ def read_db():
try:
with open(DB_FILE, 'r') as f:
return json.load(f)
- except (FileNotFoundError, json.JSONDecodeError):
+ except FileNotFoundError:
init_db()
return read_db()
+ except json.JSONDecodeError:
+ return {
+ "users": {},
+ "chatrooms": {},
+ "messages": {}
+ }
def write_db(data):
with open(DB_FILE, 'w') as f:
@@ -40,7 +46,6 @@ def index():
Virton Messenger
-
@@ -60,8 +65,7 @@ def index():
--success-color: #28a745;
--error-color: #dc3545;
--font-family: 'Inter', sans-serif;
- --ton-color: #007EE5;
- --ton-color-light: #0098EE;
+ --navbar-height: 60px;
}
* {
@@ -83,7 +87,6 @@ def index():
height: 100vh;
width: 100vw;
display: flex;
- flex-direction: column;
align-items: center;
justify-content: center;
}
@@ -94,7 +97,6 @@ def index():
display: flex;
flex-direction: column;
transition: opacity 0.3s ease;
- background-color: var(--bg-primary);
}
#login-view {
@@ -128,78 +130,38 @@ def index():
}
#app-view {
- display: none; /* Managed by JS */
+ display: none;
width: 100%;
height: 100%;
flex-direction: column;
}
-
- #content-area {
+
+ .main-content-area {
flex-grow: 1;
overflow: hidden;
- position: relative; /* For absolute positioning of view panels if needed */
- }
-
- .view-panel {
- width: 100%;
- height: 100%;
- position: absolute;
- top: 0;
- left: 0;
- display: none; /* Managed by JS */
- flex-direction: column;
- background-color: var(--bg-primary);
- animation: fadeIn 0.3s ease;
- }
-
- .view-panel.active-view {
display: flex;
+ flex-direction: row; /* Default desktop layout */
+ height: calc(100% - var(--navbar-height));
}
- @keyframes fadeIn {
- from { opacity: 0.8; }
- to { opacity: 1; }
- }
-
- .panel-header {
- padding: 16px;
- background-color: var(--bg-secondary);
- border-bottom: 1px solid var(--border-color);
+ #chatroom-list-view,
+ #users-list-view {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ width: 100%; /* Mobile default */
flex-shrink: 0;
- font-size: 1.2rem;
- font-weight: 600;
- text-align: center;
- }
-
- #chatrooms-view .panel-header,
- #users-view .panel-header,
- #my-profile-view .panel-header,
- #browser-view .panel-header {
- display: flex;
- align-items: center;
- justify-content: center;
- }
-
-
- #chatrooms-view {
- /* Special layout for chat list + chat window on desktop */
- }
-
- #chatroom-list-container {
- width: 100%; /* Mobile default */
- height: 100%;
- display: flex; /* Mobile default */
- flex-direction: column;
- background-color: var(--bg-secondary);
- overflow-y: auto;
+ background-color: var(--bg-secondary);
}
-
- #chat-window-container {
- width: 100%; /* Mobile default */
- height: 100%;
- display: none; /* Mobile default, shown by JS */
- flex-direction: column;
- background-color: var(--bg-primary);
+
+ #chat-window-view,
+ #browser-view {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ width: 100%; /* Mobile default */
+ flex-grow: 1;
+ background-color: var(--bg-primary);
}
.list-header {
@@ -223,12 +185,12 @@ def index():
background-color: var(--bg-tertiary);
border-radius: 8px;
margin-bottom: 16px;
+ word-break: break-all;
}
- #user-wallet-summary, #user-nickname-summary {
+ #user-wallet, #user-nickname {
font-size: 0.9rem;
color: var(--text-secondary);
margin-bottom: 8px;
- word-break: break-all;
}
.username-form { display: flex; gap: 8px; }
@@ -251,39 +213,27 @@ def index():
border-radius: 6px;
cursor: pointer;
font-weight: 500;
- transition: transform 0.1s ease, box-shadow 0.1s ease;
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
- .action-btn:active {
- transform: scale(0.95);
- }
- .action-btn:disabled {
- opacity: 0.5;
- cursor: not-allowed;
+ .action-btn:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 15px rgba(0, 136, 204, 0.3);
}
.action-btn.small {
padding: 8px 12px;
font-size: 0.9rem;
}
- #chatroom-list {
+ #chatroom-list,
+ #users-list {
flex-grow: 1;
overflow-y: auto;
}
- .chatroom-item {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 12px 16px;
- cursor: pointer;
- border-bottom: 1px solid var(--border-color);
- transition: background-color 0.2s ease;
- }
- .chatroom-item:hover { background-color: var(--bg-hover); }
-
+ .chatroom-item,
.user-item {
display: flex;
align-items: center;
@@ -293,9 +243,9 @@ def index():
border-bottom: 1px solid var(--border-color);
transition: background-color 0.2s ease;
}
+ .chatroom-item:hover,
.user-item:hover { background-color: var(--bg-hover); }
-
.avatar {
width: 40px;
height: 40px;
@@ -306,18 +256,27 @@ def index():
font-weight: 600;
color: white;
flex-shrink: 0;
- user-select: none;
+ font-size: 1.1rem;
}
- .list-item-info {
+ .chatroom-info,
+ .user-info {
flex-grow: 1;
overflow: hidden;
}
- .list-item-name {
+ .chatroom-name,
+ .user-nickname {
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
+ .user-address {
+ font-size: 0.8rem;
+ color: var(--text-secondary);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
.lock-icon {
width: 16px;
height: 16px;
@@ -325,14 +284,6 @@ def index():
flex-shrink: 0;
}
- #chat-window-view {
- display: none; /* Mobile default */
- flex-direction: column;
- height: 100%;
- width: 100%;
- background-color: var(--bg-primary);
- }
-
.chat-header {
display: flex;
align-items: center;
@@ -346,11 +297,7 @@ def index():
background: none;
border: none;
cursor: pointer;
- display: block; /* Mobile default */
- padding: 0;
- width: 24px;
- height: 24px;
- flex-shrink: 0;
+ display: block; /* Show on mobile by default */
}
.back-btn svg {
width: 24px;
@@ -360,17 +307,7 @@ def index():
#chat-header-title {
font-size: 1.2rem;
font-weight: 600;
- flex-grow: 1;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
}
- #chat-header-avatar {
- width: 36px;
- height: 36px;
- font-size: 0.9rem;
- }
-
#messages-container {
flex-grow: 1;
@@ -387,10 +324,10 @@ def index():
max-width: 80%;
}
.message .avatar {
- width: 32px;
- height: 32px;
+ width: 36px;
+ height: 36px;
align-self: flex-end;
- font-size: 0.8rem;
+ font-size: 1rem;
}
.message-content {
display: flex;
@@ -405,7 +342,7 @@ def index():
cursor: pointer;
}
.message-bubble {
- padding: 8px 12px;
+ padding: 10px 14px;
border-radius: 18px;
line-height: 1.4;
word-wrap: break-word;
@@ -439,7 +376,7 @@ def index():
.message-form {
display: flex;
- padding: 12px 16px;
+ padding: 16px;
gap: 12px;
background-color: var(--bg-secondary);
border-top: 1px solid var(--border-color);
@@ -459,153 +396,41 @@ def index():
#message-input:focus { border-color: var(--accent-blue); }
.send-btn {
- width: 40px;
- height: 40px;
+ width: 44px;
+ height: 44px;
border-radius: 50%;
flex-shrink: 0;
padding: 0;
}
- .send-btn svg { width: 18px; height: 18px; fill: white; }
+ .send-btn svg { width: 20px; height: 20px; fill: white; }
- #users-list-container {
- flex-grow: 1;
- overflow-y: auto;
- }
-
- #my-profile-view .profile-details {
- padding: 20px;
+ #browser-view .browser-url-bar {
display: flex;
- flex-direction: column;
- align-items: center;
- gap: 16px;
- }
- #my-profile-view .profile-details .avatar {
- width: 80px;
- height: 80px;
- font-size: 2rem;
- margin-bottom: 10px;
- }
- #my-profile-view #profile-username,
- #my-profile-view #profile-address,
- #my-profile-view #profile-balance {
- width: 100%;
- text-align: center;
- word-break: break-all;
- }
- #my-profile-view #profile-username {
- font-size: 1.5rem;
- font-weight: 600;
- }
- #my-profile-view #profile-address,
- #my-profile-view #profile-balance {
- font-size: 1rem;
- color: var(--text-secondary);
- }
- #my-profile-view #profile-balance {
- color: var(--ton-color-light);
- font-weight: 500;
- }
-
- #my-profile-view #profile-qr-code {
- background: white;
- padding: 10px;
- margin-top: 20px;
- width: fit-content;
- border-radius: 8px;
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
- }
- #my-profile-view .username-form {
- width: 100%;
- max-width: 300px;
- margin-top: 20px;
- }
-
-
- #browser-view iframe {
- width: 100%;
- flex-grow: 1;
- border: none;
+ padding: 12px 16px;
+ gap: 8px;
+ background-color: var(--bg-secondary);
+ border-bottom: 1px solid var(--border-color);
+ flex-shrink: 0;
}
- #browser-address-bar {
- display: flex;
- padding: 8px 16px;
- background-color: var(--bg-tertiary);
- gap: 8px;
- }
- #browser-address-bar input {
+ #browser-view .browser-url-input {
flex-grow: 1;
padding: 8px 12px;
border: 1px solid var(--border-color);
- background-color: var(--bg-primary);
+ background-color: var(--bg-tertiary);
color: var(--text-primary);
border-radius: 6px;
- font-size: 0.9rem;
outline: none;
+ font-size: 0.9rem;
}
- #browser-address-bar button {
- padding: 8px 12px;
- background: var(--accent-blue);
- color: white;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- }
-
+ #browser-view .browser-url-input:focus { border-color: var(--accent-blue); }
- #bottom-nav {
- display: flex;
- justify-content: space-around;
- align-items: center;
- height: 60px;
- background-color: var(--bg-secondary);
- border-top: 1px solid var(--border-color);
- flex-shrink: 0;
- }
- .nav-item {
+ #browser-view iframe {
flex-grow: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- color: var(--text-secondary);
- font-size: 0.7rem;
- transition: color 0.2s ease;
- user-select: none;
- padding: 4px 0;
- }
- .nav-item svg {
- width: 24px;
- height: 24px;
- fill: var(--text-secondary);
- margin-bottom: 4px;
- transition: fill 0.2s ease;
- }
- .nav-item.active {
- color: var(--accent-blue-light);
- }
- .nav-item.active svg {
- fill: var(--accent-blue-light);
+ width: 100%;
+ height: 100%;
+ border: none;
}
- .nav-item#qr-scanner-nav {
- position: relative;
- top: -15px;
- width: 50px;
- height: 50px;
- border-radius: 50%;
- background: linear-gradient(45deg, var(--accent-blue), var(--accent-blue-light));
- color: white;
- box-shadow: 0 4px 10px rgba(0, 136, 204, 0.4);
- flex-grow: 0;
- margin: 0 10px;
- }
- .nav-item#qr-scanner-nav svg {
- fill: white;
- margin: 0;
- }
-
-
.modal-overlay {
position: fixed;
top: 0;
@@ -631,7 +456,7 @@ def index():
}
.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 {
+ .modal-content input:not([type="checkbox"]) {
width: 100%;
padding: 12px;
margin-bottom: 16px;
@@ -642,18 +467,38 @@ def index():
font-size: 1rem;
}
.modal-actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 8px; }
+ .modal-actions.column { flex-direction: column; align-items: stretch; }
.modal-btn {
padding: 10px 20px;
border-radius: 6px;
border: none;
cursor: pointer;
font-weight: 500;
+ text-align: center;
}
.secondary-btn { background-color: var(--bg-hover); color: white; }
+ #profile-modal .modal-content { text-align: center; }
+ #profile-avatar-container { margin: 20px auto; display: inline-block; }
+ #profile-username { font-size: 1.2rem; font-weight: 600; }
+ #profile-address { color: var(--text-secondary); font-size: 0.9rem; word-break: break-all; margin-top: 8px; }
+ #profile-qr-code { background: white; padding: 10px; margin: 20px auto; width: fit-content; border-radius: 8px; }
+ #profile-modal .caption { text-align: center; color: var(--text-secondary); font-size: 0.8rem; margin-top: -10px; margin-bottom: 20px; }
+ #profile-balance { margin-top: 16px; font-size: 1rem; color: var(--text-secondary); }
+
+
+ #scanner-modal .modal-content { text-align: center; }
+ #qr-reader {
+ width: 100%;
+ border: 1px solid var(--border-color);
+ margin-top: 16px;
+ border-radius: 8px;
+ overflow: hidden;
+ }
+
#status-bar {
position: fixed;
- bottom: 70px; /* Above nav bar */
+ bottom: calc(var(--navbar-height) + 20px); /* Position above navbar */
left: 50%;
transform: translateX(-50%);
background-color: var(--bg-tertiary);
@@ -666,19 +511,77 @@ def index():
transition: opacity 0.3s, visibility 0.3s;
z-index: 2000;
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
- max-width: 90%;
- 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; }
- /* Desktop Layout */
+ .navbar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: var(--navbar-height);
+ background-color: var(--bg-secondary);
+ border-top: 1px solid var(--border-color);
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+ z-index: 900;
+ }
+ .navbar-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ flex-grow: 1;
+ height: 100%;
+ color: var(--text-secondary);
+ font-size: 0.75rem;
+ cursor: pointer;
+ transition: color 0.2s ease;
+ }
+ .navbar-item:hover {
+ color: var(--text-primary);
+ }
+ .navbar-item.active {
+ color: var(--accent-blue-light);
+ }
+ .navbar-item svg {
+ width: 24px;
+ height: 24px;
+ margin-bottom: 4px;
+ fill: currentColor; /* Use parent color */
+ }
+ .navbar-item.scan-qr-item {
+ position: relative;
+ top: -15px; /* Lift button slightly */
+ width: 50px;
+ height: 50px;
+ background: linear-gradient(45deg, var(--accent-blue), var(--accent-blue-light));
+ border-radius: 50%;
+ box-shadow: 0 5px 15px rgba(0, 136, 204, 0.3);
+ color: white;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 0; /* Hide text */
+ flex-grow: 0;
+ }
+ .navbar-item.scan-qr-item svg {
+ margin-bottom: 0;
+ width: 28px;
+ height: 28px;
+ }
+ .navbar-item.scan-qr-item:hover {
+ color: white; /* Keep color white on hover */
+ transform: translateY(-2px);
+ box-shadow: 0 7px 20px rgba(0, 136, 204, 0.4);
+ }
+
+
+ /* Desktop Styles */
@media (min-width: 768px) {
- body {
- padding: 20px;
- background-color: var(--bg-secondary);
- }
.main-container {
max-width: 1100px;
max-height: 800px;
@@ -686,68 +589,50 @@ def index():
overflow: hidden;
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
border: 1px solid var(--border-color);
- flex-direction: row;
- }
-
- #login-view {
- border-radius: 12px;
}
#app-view {
- flex-direction: row;
+ flex-direction: column; /* Keep column for desktop */
}
- #bottom-nav {
- display: none; /* Hide bottom nav on desktop */
- }
-
- #content-area {
- flex-direction: row; /* Layout views side-by-side or within a split */
- position: static; /* No absolute positioning */
+ .main-content-area {
+ flex-direction: row; /* Desktop layout */
+ height: 100%; /* Desktop uses split view, not offset by navbar */
}
- .view-panel {
- position: static; /* No absolute positioning */
- width: 100%; /* Takes full content width by default */
- }
-
- #chatrooms-view.active-view {
- display: flex; /* Ensure flex for split */
- flex-direction: row; /* Arrange list and window side by side */
- }
-
- #chatroom-list-container {
- width: 320px; /* Fixed width for list */
+ #chatroom-list-view,
+ #users-list-view {
+ width: 320px;
flex-shrink: 0;
border-right: 1px solid var(--border-color);
- display: flex; /* Always visible */
+ display: flex !important; /* Always show list on desktop */
}
- #chat-window-container {
- width: auto; /* Take remaining space */
- flex-grow: 1;
- display: flex; /* Always visible */
- }
+ #chat-window-view {
+ width: auto;
+ flex-grow: 1;
+ display: flex !important; /* Always show chat on desktop */
+ }
- .back-btn {
- display: none !important; /* Hide back button on desktop */
- }
+ #browser-view {
+ width: auto;
+ flex-grow: 1;
+ display: flex !important; /* Always show browser when active */
+ }
- .chat-header #chat-header-title {
- text-align: left;
- }
- .chat-header {
- justify-content: flex-start;
- }
+ .back-btn { display: none !important; } /* Hide back button on desktop */
- #users-view.active-view,
- #browser-view.active-view,
- #my-profile-view.active-view {
- display: flex; /* These views take the full content area */
- }
+ .navbar {
+ position: static; /* Navbar is integrated into layout or hidden on desktop */
+ height: 0; /* Make navbar height 0 to not take space */
+ border-top: none;
+ }
+ .navbar-item {
+ display: none; /* Hide navbar items on desktop */
+ }
#status-bar {
- bottom: 20px; /* Move back to bottom */
+ bottom: 20px; /* Move status bar down on desktop */
}
}
@@ -762,110 +647,100 @@ def index():
-
-
-
-
-
-
-
-

-
Выберите чат
-
Начните общение в одном из существующих чатов или создайте свой собственный.
-
-
-