webcodelab commited on
Commit
6edc57d
Β·
verified Β·
1 Parent(s): e5b5186

Update app/templates/settings.html

Browse files
Files changed (1) hide show
  1. app/templates/settings.html +235 -0
app/templates/settings.html CHANGED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.html" %}
2
+ {% block title %}Settings – Resume Ranker API{% endblock %}
3
+
4
+ {% block extra_head %}
5
+ {# No extra head elements are strictly needed here if dashboard.css covers all form/card styles #}
6
+ <style>
7
+ /* Specific styling for the settings content if not fully covered by dashboard.css */
8
+ .settings-form-group {
9
+ margin-bottom: 1.5rem;
10
+ }
11
+
12
+ .settings-form-group label {
13
+ display: block;
14
+ margin-bottom: 0.5rem;
15
+ font-weight: 600;
16
+ color: var(--text-color);
17
+ }
18
+
19
+ .settings-form-group input[type="text"],
20
+ .settings-form-group input[type="email"],
21
+ .settings-form-group input[type="password"] {
22
+ width: 100%;
23
+ padding: 0.75rem;
24
+ border: 1px solid var(--border);
25
+ border-radius: 0.5rem;
26
+ background-color: var(--input-bg);
27
+ color: var(--input-text);
28
+ box-sizing: border-box;
29
+ font-size: 1rem;
30
+ }
31
+
32
+ .settings-form-group input[readonly] {
33
+ background-color: var(--bg-light);
34
+ opacity: 0.8;
35
+ cursor: not-allowed;
36
+ }
37
+
38
+ .danger-zone .btn-danger {
39
+ background-color: var(--danger-color);
40
+ color: var(--btn-text-color);
41
+ border: none;
42
+ }
43
+
44
+ .danger-zone .btn-danger:hover {
45
+ background-color: var(--danger-hover);
46
+ }
47
+
48
+ /* Adjust mt/mb spacing if needed */
49
+ .content-padding .mt-3 { margin-top: 1rem; }
50
+ .content-padding .mt-4 { margin-top: 1.5rem; }
51
+ .content-padding .mb-4 { margin-bottom: 1.5rem; }
52
+ </style>
53
+ {% endblock %}
54
+
55
+ {% block content %}
56
+ <div class="dashboard-wrapper">
57
+ <aside class="sidebar" id="sidebar">
58
+ <div class="sidebar-header">
59
+ <div class="logo">ResumeRanker<span style="color:var(--accent)">.API</span></div>
60
+ <button class="close-sidebar" id="closeSidebar" aria-label="Close menu">
61
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
62
+ </button>
63
+ </div>
64
+ <nav class="sidebar-nav">
65
+ {# Use Flask's request.endpoint to set 'active' class #}
66
+ <a href="{{ url_for('auth.dashboard') }}" class="nav-item {% if request.endpoint == 'auth.dashboard' %}active{% endif %}">
67
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-grid"><rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="14" y="14" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect></svg>
68
+ <span>Dashboard</span>
69
+ </a>
70
+ <a href="{{ url_for('auth.api_keys') }}" class="nav-item {% if request.endpoint == 'auth.api_keys' %}active{% endif %}">
71
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-key"><path d="M19 10H5a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2z"></path><circle cx="12" cy="16" r="2"></circle><path d="M15 10V4.5a2.5 2.5 0 0 0-5 0V10"></path></svg>
72
+ <span>My API Keys</span>
73
+ </a>
74
+ <a href="{{ url_for('auth.resume_rankings') }}" class="nav-item {% if request.endpoint == 'auth.resume_rankings' %}active{% endif %}">
75
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-award"><circle cx="12" cy="8" r="7"></circle><polyline points="8.21 13.89 7 23 12 20 17 23 15.79 13.89"></polyline></svg>
76
+ <span>Resume Rankings</span>
77
+ </a>
78
+ <a href="{{ url_for('auth.try_api') }}" class="nav-item {% if request.endpoint == 'auth.try_api' %}active{% endif %}">
79
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-play-circle"><circle cx="12" cy="12" r="10"></circle><polygon points="10 8 16 12 10 16 10 8"></polygon></svg>
80
+ <span>Try It Now</span>
81
+ </a>
82
+ <a href="{{ url_for('auth.api_docs') }}" class="nav-item {% if request.endpoint == 'auth.api_docs' %}active{% endif %}">
83
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-book"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20V6.5A2.5 2.5 0 0 0 17.5 4h-11A2.5 2.5 0 0 0 4 6.5v13z"></path><path d="M11 6h6"></path><path d="M11 10h6"></path><path d="M11 14h6"></path></svg>
84
+ <span>API Docs</span>
85
+ </a>
86
+ <a href="{{ url_for('auth.settings') }}" class="nav-item active"> {# This page is active #}
87
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-settings"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l-.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
88
+ <span>Settings</span>
89
+ </a>
90
+ <a href="{{ url_for('auth.logout') }}" class="nav-item logout-item">
91
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-log-out"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="17 16 22 12 17 8"></polyline><line x1="22" y1="12" x2="10" y2="12"></line></svg>
92
+ <span>Logout</span>
93
+ </a>
94
+ </nav>
95
+ </aside>
96
+
97
+ <div class="main-content-area" id="mainContentArea">
98
+ <header class="dashboard-header">
99
+ <button class="hamburger-dashboard" id="hamburgerDashboard" aria-label="Open sidebar menu">
100
+ <span></span><span></span><span></span>
101
+ </button>
102
+ <div class="user-settings">
103
+ <span class="user-name">{{ user.username }}</span>
104
+ <div class="user-avatar">
105
+ <img src="https://ui-avatars.com/api/?name={{ user.username | urlencode }}&background=2563eb&color=fff&size=30" alt="User Avatar">
106
+ </div>
107
+ <button class="theme-toggle" id="themeToggleDashboard" aria-label="Toggle dark mode">πŸŒ™</button>
108
+ </div>
109
+ </header>
110
+
111
+ <div class="content-padding">
112
+ <h1 class="welcome-title">Account Settings</h1>
113
+ <p class="subtitle">Manage your profile, password, and preferences.</p>
114
+
115
+ {% with messages = get_flashed_messages(with_categories=true) %}
116
+ {% if messages %}
117
+ {% for category, message in messages %}
118
+ <div class="flash-message flash-{{ category }}">{{ message }}</div>
119
+ {% endfor %}
120
+ {% endif %}
121
+ {% endwith %}
122
+
123
+ <div class="section-card profile-settings">
124
+ <h3 class="section-title">Profile Information</h3>
125
+ <form action="{{ url_for('auth.update_profile') }}" method="POST">
126
+ <div class="settings-form-group">
127
+ <label for="username">Username</label>
128
+ <input type="text" id="username" name="username" value="{{ user.username }}" readonly>
129
+ </div>
130
+ <div class="settings-form-group">
131
+ <label for="email">Email Address</label>
132
+ <input type="email" id="email" name="email" value="{{ user.email }}" required>
133
+ </div>
134
+ {# Add more profile fields if you have them, e.g., first_name, last_name #}
135
+ <button type="submit" class="btn primary-btn">Update Profile</button>
136
+ </form>
137
+ </div>
138
+
139
+ <div class="section-card password-settings mt-4">
140
+ <h3 class="section-title">Change Password</h3>
141
+ <form action="{{ url_for('auth.change_password') }}" method="POST">
142
+ <div class="settings-form-group">
143
+ <label for="current_password">Current Password</label>
144
+ <input type="password" id="current_password" name="current_password" required>
145
+ </div>
146
+ <div class="settings-form-group">
147
+ <label for="new_password">New Password</label>
148
+ <input type="password" id="new_password" name="new_password" required>
149
+ </div>
150
+ <div class="settings-form-group">
151
+ <label for="confirm_new_password">Confirm New Password</label>
152
+ <input type="password" id="confirm_new_password" name="confirm_new_password" required>
153
+ </div>
154
+ <button type="submit" class="btn primary-btn">Change Password</button>
155
+ </form>
156
+ </div>
157
+
158
+ <div class="section-card theme-settings mt-4">
159
+ <h3 class="section-title">Theme Settings</h3>
160
+ <p class="section-description">Choose your preferred application theme.</p>
161
+ <div class="settings-form-group">
162
+ <label for="theme_select">Select Theme:</label>
163
+ <select id="theme_select" class="form-input" onchange="setTheme(this.value)">
164
+ <option value="light" {% if user.theme == 'light' %}selected{% endif %}>Light</option>
165
+ <option value="dark" {% if user.theme == 'dark' %}selected{% endif %}>Dark</option>
166
+ </select>
167
+ </div>
168
+ </div>
169
+
170
+ <div class="section-card danger-zone mt-4">
171
+ <h3 class="section-title">Danger Zone</h3>
172
+ <p class="section-description">Proceed with caution. These actions are irreversible.</p>
173
+ <form action="{{ url_for('auth.delete_account') }}" method="POST" onsubmit="return confirm('Are you sure you want to delete your account? This action cannot be undone.');">
174
+ <button type="submit" class="btn btn-danger">Delete My Account</button>
175
+ </form>
176
+ </div>
177
+
178
+ <p class="mt-4"><a href="{{ url_for('auth.dashboard') }}" class="btn secondary-btn">← Back to Dashboard</a></p>
179
+ </div>
180
+ </div>
181
+ </div>
182
+ {% endblock %}
183
+
184
+ {% block extra_scripts %}
185
+ <script>
186
+ // Theme toggle (specific to dashboard header) - duplicated for consistency across pages
187
+ const themeToggleDashboard = document.getElementById('themeToggleDashboard');
188
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
189
+ function setTheme(theme) {
190
+ document.documentElement.setAttribute('data-theme', theme);
191
+ localStorage.setItem('theme', theme);
192
+ themeToggleDashboard.textContent = theme === 'dark' ? 'β˜€οΈ' : 'πŸŒ™';
193
+ // Also update the select dropdown if it exists
194
+ const themeSelect = document.getElementById('theme_select');
195
+ if (themeSelect) {
196
+ themeSelect.value = theme;
197
+ }
198
+ }
199
+ const savedTheme = localStorage.getItem('theme');
200
+ setTheme(savedTheme || (prefersDark ? 'dark' : 'light'));
201
+ themeToggleDashboard.onclick = () => {
202
+ const current = document.documentElement.getAttribute('data-theme');
203
+ setTheme(current === 'dark' ? 'light' : 'dark');
204
+ };
205
+
206
+ // Sidebar toggle for mobile - duplicated for consistency across pages
207
+ const hamburgerDashboard = document.getElementById('hamburgerDashboard');
208
+ const sidebar = document.getElementById('sidebar');
209
+ const mainContentArea = document.getElementById('mainContentArea');
210
+ const closeSidebarBtn = document.getElementById('closeSidebar');
211
+
212
+ hamburgerDashboard.onclick = () => {
213
+ sidebar.classList.add('open');
214
+ mainContentArea.classList.add('shifted');
215
+ };
216
+ closeSidebarBtn.onclick = () => {
217
+ sidebar.classList.remove('open');
218
+ mainContentArea.classList.remove('shifted');
219
+ };
220
+ mainContentArea.onclick = (event) => {
221
+ if (sidebar.classList.contains('open') && !sidebar.contains(event.target) && !hamburgerDashboard.contains(event.target)) {
222
+ sidebar.classList.remove('open');
223
+ mainContentArea.classList.remove('shifted');
224
+ }
225
+ };
226
+ Array.from(sidebar.getElementsByClassName('nav-item')).forEach(item => {
227
+ item.onclick = () => {
228
+ if (window.innerWidth <= 900) {
229
+ sidebar.classList.remove('open');
230
+ mainContentArea.classList.remove('shifted');
231
+ }
232
+ };
233
+ });
234
+ </script>
235
+ {% endblock %}