2026-02-20 12:27:52 +01:00
<!DOCTYPE html>
< html lang = "en" >
< head >
2026-05-19 17:23:38 +02:00
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
2026-05-30 01:06:32 +02:00
<!-- Declares the page supports both modes. Switching between them is
driven by the CSS `color-scheme` property (via the `data-color-scheme`
attribute on <html> set by theme-init.js), not by mutating this tag. -->
< meta name = "color-scheme" content = "light dark" >
2026-05-19 17:23:38 +02:00
< title > OxiCloud — My Profile</ title >
< link rel = "icon" type = "image/svg+xml" href = "/logo/logo-plain.svg" >
< script src = "/js/core/theme-init.js" ></ script >
< link rel = "stylesheet" href = "/css/main.css" >
< link rel = "stylesheet" href = "/css/views/profile.css" >
2026-02-20 12:27:52 +01:00
</ head >
< body >
< div class = "profile-header" >
< div class = "profile-header-left" >
< a href = "/" class = "profile-logo-link link-reset-flex" >
< div class = "profile-logo" >
< svg viewBox = "0 0 500 500" >
< path d = "M345 310c32 0 58-26 58-58s-26-58-58-58c-6.2 0-12 0.9-17.5 2.7C318 166 289 143 255 143c-34.3 0-63.1 22.6-73 53.7C176.9 195.7 171 195 165 195c-32 0-58 26-58 58s26 58 58 58h180z" />
</ svg >
</ div >
< span class = "profile-title-text" > OxiCloud</ span >
</ a >
2026-03-09 00:08:34 +01:00
< span class = "profile-title-separator" > · < span data-i18n = "profile.page_title" > Profile</ span ></ span >
2026-02-20 12:27:52 +01:00
</ div >
< div class = "profile-header-right" >
2026-03-09 00:08:34 +01:00
< a href = "/" >< i class = "fas fa-arrow-left" ></ i > < span data-i18n = "profile.back_to_app" > Back to OxiCloud</ span ></ a >
2026-02-20 12:27:52 +01:00
</ div >
</ div >
< div class = "profile-container" >
2026-03-09 00:08:34 +01:00
< div id = "loading" >< i class = "fas fa-circle-notch" ></ i > < span data-i18n = "profile.loading" > Loading…</ span ></ div >
2026-03-05 17:07:48 -05:00
< div id = "auth-error" class = "hidden" >
2026-02-20 12:27:52 +01:00
< div class = "err-icon" >< i class = "fas fa-lock" ></ i ></ div >
2026-03-09 00:08:34 +01:00
< h2 data-i18n = "profile.not_authenticated" > Not Authenticated</ h2 >
< p data-i18n = "profile.not_authenticated_desc" > Please sign in to view your profile.</ p >
< a href = "/login" >< i class = "fas fa-sign-in-alt" ></ i > < span data-i18n = "profile.sign_in" > Sign in</ span ></ a >
2026-02-20 12:27:52 +01:00
</ div >
2026-03-05 17:07:48 -05:00
< div id = "main-content" class = "hidden" >
2026-02-20 12:27:52 +01:00
< div class = "profile-card" >
< div class = "avatar-section" >
2026-05-26 00:50:38 +02:00
< div class = "avatar-large-wrap" >
< div class = "avatar-large" id = "p-avatar" > —</ div >
< button class = "avatar-edit-btn hidden" id = "p-avatar-edit-btn" data-i18n-title = "profile.edit_photo" title = "Edit photo" >
< i class = "fas fa-pencil-alt" ></ i >
</ button >
</ div >
2026-02-20 12:27:52 +01:00
< div class = "avatar-info" >
< h1 id = "p-username" > —</ h1 >
< div class = "email" id = "p-email" > —</ div >
< span class = "role-badge" id = "p-role-badge" > —</ span >
2026-05-26 00:50:38 +02:00
< p class = "avatar-oidc-note hidden" id = "p-avatar-oidc-note" data-i18n = "profile.photo_managed_by_oidc" > Photo managed by your identity provider.</ p >
</ div >
</ div >
<!-- Photo edit panel (local accounts only) -->
< div class = "avatar-edit-panel hidden" id = "p-avatar-edit-panel" >
< div class = "avatar-edit-tabs" >
< button class = "avatar-tab active" id = "p-tab-url" data-i18n = "profile.photo_tab_url" > URL</ button >
< button class = "avatar-tab" id = "p-tab-upload" data-i18n = "profile.photo_tab_upload" > Upload</ button >
</ div >
<!-- URL input mode -->
< div class = "avatar-tab-pane" id = "p-pane-url" >
< input type = "url" id = "p-image-url" class = "avatar-url-input"
data-i18n-placeholder = "profile.photo_url_placeholder"
placeholder = "https://example.com/photo.jpg" >
< small class = "avatar-hint" data-i18n = "profile.photo_url_hint" > https://, http://, or data:image/…;base64,… accepted</ small >
</ div >
<!-- Upload mode -->
< div class = "avatar-tab-pane hidden" id = "p-pane-upload" >
< label class = "avatar-file-label" for = "p-image-file" >
< i class = "fas fa-cloud-upload-alt" ></ i >
< span data-i18n = "profile.photo_choose_file" > Choose a photo (PNG, JPEG, WebP)</ span >
</ label >
< input type = "file" id = "p-image-file" class = "avatar-file-input"
accept = "image/png,image/jpeg,image/webp" >
< img class = "avatar-preview hidden" id = "p-image-preview" alt = "Preview" src = "" >
< small class = "avatar-hint" data-i18n = "profile.photo_resize_note" > Images larger than 512 × 512 px are automatically resized.</ small >
</ div >
< div class = "avatar-edit-actions" >
< button class = "btn btn-primary" id = "p-avatar-save" data-i18n = "profile.photo_save" > Save</ button >
< button class = "btn btn-danger-sm" id = "p-avatar-remove" data-i18n = "profile.photo_remove" > Remove photo</ button >
< button class = "btn btn-secondary" id = "p-avatar-cancel" data-i18n = "profile.photo_cancel" > Cancel</ button >
2026-02-20 12:27:52 +01:00
</ div >
2026-05-26 00:50:38 +02:00
< div id = "p-avatar-status" ></ div >
2026-02-20 12:27:52 +01:00
</ div >
</ div >
< div class = "profile-card" >
2026-03-09 00:08:34 +01:00
< h2 >< i class = "fas fa-id-card" ></ i > < span data-i18n = "profile.account_details" > Account Details</ span ></ h2 >
2026-02-20 12:27:52 +01:00
< div class = "info-grid" >
< div class = "info-item" >
2026-03-09 00:08:34 +01:00
< div class = "info-label" >< i class = "fas fa-user" ></ i > < span data-i18n = "profile.username" > Username</ span ></ div >
2026-02-20 12:27:52 +01:00
< div class = "info-value" id = "p-detail-username" > —</ div >
</ div >
< div class = "info-item" >
2026-03-09 00:08:34 +01:00
< div class = "info-label" >< i class = "fas fa-envelope" ></ i > < span data-i18n = "profile.email" > Email</ span ></ div >
2026-02-20 12:27:52 +01:00
< div class = "info-value" id = "p-detail-email" > —</ div >
</ div >
< div class = "info-item" >
2026-03-09 00:08:34 +01:00
< div class = "info-label" >< i class = "fas fa-shield-alt" ></ i > < span data-i18n = "profile.role" > Role</ span ></ div >
2026-02-20 12:27:52 +01:00
< div class = "info-value" id = "p-detail-role" > —</ div >
</ div >
< div class = "info-item" >
2026-03-09 00:08:34 +01:00
< div class = "info-label" >< i class = "fas fa-clock" ></ i > < span data-i18n = "profile.last_login" > Last Login</ span ></ div >
2026-02-20 12:27:52 +01:00
< div class = "info-value" id = "p-detail-login" > —</ div >
</ div >
</ div >
</ div >
2026-06-03 09:35:38 +02:00
< div class = "profile-card" id = "profile-edit-section" >
< h2 >< i class = "fas fa-id-badge" ></ i > < span data-i18n = "profile.edit_profile" > Edit Profile</ span ></ h2 >
< div id = "profile-edit-oidc-note" class = "alert alert-info hidden" >
< i class = "fas fa-info-circle" ></ i >
< span data-i18n = "profile.edit_oidc_managed" > To change your information (name, first name, profile picture, …), please update it at your identity provider. Your changes will appear on your next sign-in.</ span >
</ div >
< form id = "profile-edit-form" >
< div class = "form-group" >
< label for = "profile-edit-username" data-i18n = "profile.username" > Username</ label >
< input type = "text" id = "profile-edit-username" maxlength = "64" autocomplete = "username"
data-i18n-placeholder = "profile.username_placeholder" placeholder = "e.g. alice" >
< small id = "profile-edit-username-hint" data-i18n = "profile.username_claim_hint" > 2– 64 characters, letters/digits/dot/dash/underscore. Once chosen, the username can't be changed (DAV/NextCloud clients depend on it).</ small >
</ div >
< div class = "form-group" >
< label for = "profile-edit-given-name" data-i18n = "profile.given_name" > First name</ label >
< input type = "text" id = "profile-edit-given-name" maxlength = "128" autocomplete = "given-name" >
</ div >
< div class = "form-group" >
< label for = "profile-edit-family-name" data-i18n = "profile.family_name" > Last name</ label >
< input type = "text" id = "profile-edit-family-name" maxlength = "128" autocomplete = "family-name" >
</ div >
< button type = "submit" class = "btn btn-primary" id = "profile-edit-submit" >
< i class = "fas fa-save" ></ i > < span data-i18n = "profile.save_profile" > Save changes</ span >
</ button >
< div id = "profile-edit-status" ></ div >
</ form >
</ div >
2026-02-20 12:27:52 +01:00
< div class = "profile-card" >
2026-03-09 00:08:34 +01:00
< h2 >< i class = "fas fa-hdd" ></ i > < span data-i18n = "profile.storage" > Storage</ span ></ h2 >
2026-02-20 12:27:52 +01:00
< div class = "storage-stats" >
< div class = "storage-stat" >
< div class = "stat-value" id = "p-storage-used" > —</ div >
2026-03-09 00:08:34 +01:00
< div class = "stat-label" data-i18n = "profile.used" > Used</ div >
2026-02-20 12:27:52 +01:00
</ div >
< div class = "storage-stat" >
< div class = "stat-value" id = "p-storage-quota" > —</ div >
2026-03-09 00:08:34 +01:00
< div class = "stat-label" data-i18n = "profile.quota" > Quota</ div >
2026-02-20 12:27:52 +01:00
</ div >
< div class = "storage-stat" >
< div class = "stat-value" id = "p-storage-pct" > —</ div >
2026-03-09 00:08:34 +01:00
< div class = "stat-label" data-i18n = "profile.usage" > Usage</ div >
2026-02-20 12:27:52 +01:00
</ div >
</ div >
< div class = "storage-bar-wrap" >
< div class = "storage-bar" >< div class = "storage-fill green width-zero" id = "p-storage-bar" ></ div ></ div >
< div class = "storage-text" id = "p-storage-text" > —</ div >
</ div >
</ div >
2026-03-04 14:02:15 +01:00
< div class = "profile-card" id = "app-passwords-section" >
2026-03-09 00:08:34 +01:00
< h2 >< i class = "fas fa-key" ></ i > < span data-i18n = "profile.app_passwords" > App Passwords</ span ></ h2 >
< p class = "app-pw-desc" data-i18n = "profile.app_pw_desc" > Generate passwords for WebDAV, CalDAV, and CardDAV clients. Each password is shown only once.</ p >
2026-03-04 14:02:15 +01:00
< div class = "app-pw-create" >
2026-03-09 00:08:34 +01:00
< input type = "text" id = "app-pw-label" data-i18n-placeholder = "profile.app_pw_label_placeholder" placeholder = "Label (e.g. Thunderbird, macOS)" maxlength = "128" >
< button class = "btn btn-primary" id = "app-pw-generate" >< i class = "fas fa-plus" ></ i > < span data-i18n = "profile.generate" > Generate</ span ></ button >
2026-03-04 14:02:15 +01:00
</ div >
2026-03-05 16:18:30 -05:00
< div id = "app-pw-created" class = "app-pw-created hidden" >
2026-03-09 00:08:34 +01:00
< div class = "app-pw-created-label" >< span data-i18n = "profile.new_password_for" > New password for</ span > < strong id = "app-pw-created-label" ></ strong > :</ div >
2026-03-04 14:02:15 +01:00
< div class = "app-pw-created-value" >
< code id = "app-pw-created-password" ></ code >
2026-03-09 00:08:34 +01:00
< button class = "btn btn-copy" id = "app-pw-copy-btn" data-i18n-title = "profile.copy_to_clipboard" title = "Copy to clipboard" >< i class = "fas fa-copy" ></ i ></ button >
2026-03-04 14:02:15 +01:00
</ div >
2026-03-09 00:08:34 +01:00
< small data-i18n = "profile.copy_warning" > Copy this password now. You won't be able to see it again.</ small >
2026-03-04 14:02:15 +01:00
</ div >
< div id = "app-pw-status" ></ div >
< table class = "app-pw-table" id = "app-pw-table" >
< thead >
2026-03-09 00:08:34 +01:00
< tr >< th data-i18n = "profile.col_label" > Label</ th >< th data-i18n = "profile.col_created" > Created</ th >< th data-i18n = "profile.col_last_used" > Last Used</ th >< th data-i18n = "profile.col_status" > Status</ th >< th ></ th ></ tr >
2026-03-04 14:02:15 +01:00
</ thead >
< tbody id = "app-pw-tbody" ></ tbody >
</ table >
2026-03-09 00:08:34 +01:00
< div id = "app-pw-empty" class = "app-pw-empty hidden" data-i18n = "profile.no_app_passwords" > No app passwords yet.</ div >
2026-03-04 14:02:15 +01:00
2026-03-05 16:18:30 -05:00
< div id = "app-pw-auto-section" class = "app-pw-auto-section hidden" >
< button class = "app-pw-auto-toggle" id = "app-pw-auto-toggle" >
2026-03-04 14:02:15 +01:00
< i class = "fas fa-chevron-right" id = "app-pw-auto-chevron" ></ i >
2026-03-09 00:08:34 +01:00
< span data-i18n = "profile.client_sessions" > Client sessions</ span >
2026-03-04 14:02:15 +01:00
< span class = "app-pw-auto-count" id = "app-pw-auto-count" > 0</ span >
</ button >
2026-03-05 16:18:30 -05:00
< div id = "app-pw-auto-body" class = "hidden" >
2026-03-09 00:08:34 +01:00
< p class = "app-pw-auto-desc" data-i18n = "profile.client_sessions_desc" > Auto-generated when you connect a Nextcloud-compatible client.</ p >
2026-03-04 14:02:15 +01:00
< table class = "app-pw-table" id = "app-pw-auto-table" >
< thead >
2026-03-09 00:08:34 +01:00
< tr >< th data-i18n = "profile.col_client" > Client</ th >< th data-i18n = "profile.col_created" > Created</ th >< th data-i18n = "profile.col_last_used" > Last Used</ th >< th ></ th ></ tr >
2026-03-04 14:02:15 +01:00
</ thead >
< tbody id = "app-pw-auto-tbody" ></ tbody >
</ table >
</ div >
</ div >
</ div >
2026-02-20 12:27:52 +01:00
< div class = "profile-card" id = "password-section" >
2026-03-09 00:08:34 +01:00
< h2 >< i class = "fas fa-key" ></ i > < span data-i18n = "profile.change_password" > Change Password</ span ></ h2 >
2026-03-05 13:15:34 +01:00
< form id = "password-form" >
2026-02-20 12:27:52 +01:00
< div class = "form-group" >
2026-03-09 00:08:34 +01:00
< label for = "current-password" data-i18n = "profile.current_password" > Current Password</ label >
2026-02-20 12:27:52 +01:00
< input type = "password" id = "current-password" required autocomplete = "current-password" >
</ div >
< div class = "form-group" >
2026-03-09 00:08:34 +01:00
< label for = "new-password" data-i18n = "profile.new_password" > New Password</ label >
2026-02-20 12:27:52 +01:00
< input type = "password" id = "new-password" required minlength = "8" autocomplete = "new-password" >
2026-03-09 00:08:34 +01:00
< small data-i18n = "profile.min_8_chars" > At least 8 characters</ small >
2026-02-20 12:27:52 +01:00
</ div >
< div class = "form-group" >
2026-03-09 00:08:34 +01:00
< label for = "confirm-password" data-i18n = "profile.confirm_password" > Confirm New Password</ label >
2026-02-20 12:27:52 +01:00
< input type = "password" id = "confirm-password" required minlength = "8" autocomplete = "new-password" >
</ div >
2026-03-09 00:08:34 +01:00
< button type = "submit" class = "btn btn-primary" id = "pw-submit" >< i class = "fas fa-save" ></ i > < span data-i18n = "profile.update_password" > Update Password</ span ></ button >
2026-02-20 12:27:52 +01:00
< div id = "pw-status" ></ div >
</ form >
</ div >
</ div >
</ div >
2026-04-13 15:09:10 +02:00
< script type = "module" src = "/js/views/profile/profile.js" ></ script >
2026-02-20 12:27:52 +01:00
</ body >
</ html >