visual continunity
This commit is contained in:
@@ -7,4 +7,4 @@
|
||||
@import url('./base/forms.css');
|
||||
@import url('./base/animations.css');
|
||||
@import url('./base/a11y.css');
|
||||
@import url('./legacy.css');
|
||||
@import url('./ported.css');
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/* Vendored layout/component CSS ported verbatim from the original static/css.
|
||||
* These are token-based and global; the Svelte components emit the same class
|
||||
* names and DOM so the new app matches the original look. Kept byte-faithful
|
||||
* (linters ignore this dir) — restyle via tokens in variables.css, not here. */
|
||||
@import url('./legacy/sidebar.css');
|
||||
@import url('./legacy/topbar.css');
|
||||
@import url('./legacy/content.css');
|
||||
@import url('./legacy/buttons.css');
|
||||
@import url('./legacy/breadcrumb.css');
|
||||
@import url('./legacy/fileManager.css');
|
||||
@import url('./legacy/resourceList.css');
|
||||
@import url('./legacy/skeleton.css');
|
||||
@import url('./legacy/auth.css');
|
||||
@@ -0,0 +1,18 @@
|
||||
/* Layout/component CSS ported verbatim from the OxiCloud frontend's static/css.
|
||||
* These are token-based and global; the Svelte components emit the same class
|
||||
* names and DOM so the rewrite matches the established design. Kept byte-faithful
|
||||
* (linters ignore this dir) — restyle via tokens in variables.css, not here. */
|
||||
@import url('./ported/sidebar.css');
|
||||
@import url('./ported/topbar.css');
|
||||
@import url('./ported/content.css');
|
||||
@import url('./ported/buttons.css');
|
||||
@import url('./ported/uploadDropdown.css');
|
||||
@import url('./ported/breadcrumb.css');
|
||||
@import url('./ported/fileManager.css');
|
||||
@import url('./ported/resourceList.css');
|
||||
@import url('./ported/batchToolbar.css');
|
||||
@import url('./ported/skeleton.css');
|
||||
@import url('./ported/notifications.css');
|
||||
@import url('./ported/userMenu.css');
|
||||
@import url('./ported/auth.css');
|
||||
@import url('./ported/music.css');
|
||||
@@ -0,0 +1,101 @@
|
||||
/* Multi-Select – batch action toolbar
|
||||
* Per-item checkbox styles (.file-item .checkbox-cell, .list-header.selection-mode)
|
||||
* live in resourceList.css alongside the item renderer. */
|
||||
|
||||
.batch-selection-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-4);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.batch-selection-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: var(--color-multiselect-bg);
|
||||
color: var(--color-multiselect-text);
|
||||
padding: var(--space-2-5) var(--space-5);
|
||||
border-radius: var(--radius-2xl);
|
||||
overflow: hidden;
|
||||
margin-right: var(--space-3);
|
||||
height: 60px;
|
||||
transform: translateY(-8px);
|
||||
transition:
|
||||
opacity 0.2s,
|
||||
max-height 0.25s,
|
||||
transform 0.2s,
|
||||
margin 0.2s,
|
||||
padding 0.2s;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.batch-bar-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--color-multiselect-text-faint);
|
||||
cursor: pointer;
|
||||
font-size: var(--text-base);
|
||||
padding: var(--space-1) var(--space-1-5);
|
||||
border-radius: var(--radius-md);
|
||||
transition:
|
||||
background 0.15s,
|
||||
color 0.15s;
|
||||
}
|
||||
|
||||
.batch-bar-close:hover {
|
||||
background: var(--color-multiselect-hover-bg);
|
||||
color: var(--color-multiselect-text);
|
||||
}
|
||||
|
||||
.batch-bar-count {
|
||||
font-size: var(--text-base);
|
||||
font-weight: var(--weight-semibold);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.batch-bar-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1-5);
|
||||
}
|
||||
|
||||
.batch-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1-5);
|
||||
padding: 7px var(--space-3-5);
|
||||
border: none;
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--color-multiselect-hover-bg);
|
||||
color: var(--color-multiselect-action-text);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--weight-medium);
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.batch-btn:hover {
|
||||
background: var(--color-multiselect-action-hover);
|
||||
}
|
||||
|
||||
.batch-btn-danger {
|
||||
background: var(--color-multiselect-danger-bg);
|
||||
color: var(--color-multiselect-danger-text);
|
||||
}
|
||||
|
||||
.batch-btn-danger:hover {
|
||||
background: var(--color-multiselect-danger-active);
|
||||
color: var(--color-multiselect-danger-text-active);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.batch-btn span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.batch-btn {
|
||||
padding: 7px var(--space-2-5);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,371 @@
|
||||
/* Notification */
|
||||
.notification {
|
||||
position: absolute;
|
||||
top: 70px;
|
||||
right: 20px;
|
||||
background-color: var(--color-notification-bg);
|
||||
width: 250px;
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: 0 5px 15px var(--color-shadow);
|
||||
padding: 15px;
|
||||
border-left: 4px solid var(--color-accent);
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
|
||||
[dir="rtl"] & {
|
||||
left: 20px;
|
||||
border-right: 4px solid var(--color-accent);
|
||||
right: unset;
|
||||
border-left: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-title {
|
||||
font-weight: var(--weight-bold);
|
||||
font-size: var(--text-base);
|
||||
margin-bottom: 5px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.notification-message {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
/* Notification banner */
|
||||
.notification-banner {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
padding: 15px var(--space-5);
|
||||
background-color: var(--color-notification-bg);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: 0 4px 12px var(--color-shadow);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
max-width: 400px;
|
||||
z-index: 2000;
|
||||
transform: translateY(-100px);
|
||||
opacity: 0;
|
||||
transition:
|
||||
transform 0.3s,
|
||||
opacity 0.3s;
|
||||
}
|
||||
|
||||
.notification-banner.active {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.notification-banner.success {
|
||||
border-left: 4px solid var(--color-success-border);
|
||||
}
|
||||
|
||||
.notification-banner.error {
|
||||
border-left: 4px solid var(--color-danger-bg);
|
||||
}
|
||||
|
||||
.close-notification-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: var(--text-lg);
|
||||
cursor: pointer;
|
||||
color: var(--color-text-placeholder);
|
||||
margin-left: var(--space-2-5);
|
||||
}
|
||||
|
||||
/* Notification Bell */
|
||||
.notif-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.notif-bell-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: var(--text-lg);
|
||||
color: var(--color-text-subtle);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.notif-bell-btn:hover {
|
||||
background: var(--color-accent-bg-sm);
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.notif-bell-btn.active {
|
||||
color: var(--color-accent);
|
||||
background: var(--color-accent-ring);
|
||||
}
|
||||
|
||||
.notif-badge {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
min-width: 16px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--color-notification-badge);
|
||||
color: var(--color-notification-bg);
|
||||
font-size: 10px;
|
||||
font-weight: var(--weight-bold);
|
||||
text-align: center;
|
||||
padding: 0 var(--space-1);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes bellRing {
|
||||
0%,
|
||||
100% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
13% {
|
||||
transform: rotate(22deg);
|
||||
}
|
||||
26% {
|
||||
transform: rotate(-22deg);
|
||||
}
|
||||
39% {
|
||||
transform: rotate(14deg);
|
||||
}
|
||||
52% {
|
||||
transform: rotate(-14deg);
|
||||
}
|
||||
65% {
|
||||
transform: rotate(8deg);
|
||||
}
|
||||
78% {
|
||||
transform: rotate(-8deg);
|
||||
}
|
||||
91% {
|
||||
transform: rotate(3deg);
|
||||
}
|
||||
}
|
||||
|
||||
.notif-bell-btn.ring {
|
||||
animation: bellRing 1s ease;
|
||||
}
|
||||
|
||||
.notif-panel {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 10px);
|
||||
right: -40px;
|
||||
width: 380px;
|
||||
max-height: 480px;
|
||||
background: var(--color-notification-bg);
|
||||
border-radius: var(--radius-3xl);
|
||||
box-shadow:
|
||||
0 12px 40px var(--color-shadow-md),
|
||||
0 0 0 1px var(--color-shadow-xs);
|
||||
z-index: 2000;
|
||||
overflow: hidden;
|
||||
animation: notifPanelIn 0.2s ease-out;
|
||||
}
|
||||
|
||||
.notif-wrapper.open .notif-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@keyframes notifPanelIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-8px) scale(0.97);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.notif-panel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--space-3-5) var(--space-4);
|
||||
border-bottom: 1px solid var(--color-border-xfaint);
|
||||
}
|
||||
|
||||
.notif-panel-title {
|
||||
font-weight: var(--weight-semibold);
|
||||
font-size: 15px;
|
||||
color: var(--color-text-heading);
|
||||
}
|
||||
|
||||
.notif-clear-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: var(--color-text-faint);
|
||||
font-size: var(--text-base);
|
||||
padding: var(--space-1) var(--space-2);
|
||||
border-radius: var(--radius-md);
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.notif-clear-btn:hover {
|
||||
color: var(--color-accent);
|
||||
background: var(--color-accent-bg-sm);
|
||||
}
|
||||
|
||||
.notif-panel-body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
max-height: 400px;
|
||||
/* Thin, neutral scrollbar — replaces the heavy global accent bar that read
|
||||
as amateur in the panel. */
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--color-border-medium) transparent;
|
||||
}
|
||||
|
||||
.notif-panel-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.notif-panel-body::-webkit-scrollbar-thumb {
|
||||
background: var(--color-border-medium);
|
||||
border-radius: var(--radius-full);
|
||||
}
|
||||
|
||||
.notif-panel-body::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.notif-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--space-10) var(--space-5);
|
||||
color: var(--color-text-faint);
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.notif-empty i {
|
||||
font-size: var(--text-3xl);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.notif-empty span {
|
||||
font-size: var(--text-base);
|
||||
}
|
||||
|
||||
.notif-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
gap: var(--space-3);
|
||||
border-bottom: 1px solid var(--color-bg-subtle);
|
||||
transition: background 0.15s;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.notif-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.notif-item:hover {
|
||||
background: var(--color-bg-hover);
|
||||
}
|
||||
|
||||
.notif-item-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: var(--radius-lg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
font-size: var(--text-base);
|
||||
}
|
||||
|
||||
.notif-item-icon.upload {
|
||||
background: var(--color-accent-ring);
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.notif-item-icon.success {
|
||||
background: var(--color-success-ring);
|
||||
color: var(--color-notification-success);
|
||||
}
|
||||
|
||||
.notif-item-icon.error {
|
||||
background: var(--color-notification-error-ring);
|
||||
color: var(--color-notification-error);
|
||||
}
|
||||
|
||||
.notif-item-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.notif-item-title {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--weight-semibold);
|
||||
color: var(--color-text-heading);
|
||||
margin-bottom: var(--space-0-5);
|
||||
}
|
||||
|
||||
.notif-item-text {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--color-text-subtle);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.notif-item-time {
|
||||
font-size: var(--text-2xs);
|
||||
color: var(--color-text-faint);
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.notif-upload-progress {
|
||||
margin-top: var(--space-1-5);
|
||||
}
|
||||
|
||||
.notif-upload-bar {
|
||||
height: 3px;
|
||||
background: var(--color-bg-empty);
|
||||
border-radius: var(--radius-xs);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.notif-upload-fill {
|
||||
height: 100%;
|
||||
background: var(--color-accent);
|
||||
width: 0%;
|
||||
transition: width 0.2s ease;
|
||||
border-radius: var(--radius-xs);
|
||||
}
|
||||
|
||||
.notif-upload-fill.done {
|
||||
background: var(--color-notification-success);
|
||||
}
|
||||
|
||||
.notif-upload-fill.error {
|
||||
background: var(--color-notification-error);
|
||||
}
|
||||
|
||||
.notif-upload-detail {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.notif-upload-pct,
|
||||
.notif-upload-stats {
|
||||
font-size: var(--text-2xs);
|
||||
color: var(--color-text-faint);
|
||||
}
|
||||
+20
@@ -392,6 +392,12 @@
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* List rows expose the individual action buttons inline (on hover), so the
|
||||
corner kebab is redundant here — it's the grid view's affordance. */
|
||||
.files-list-view .file-item .action-cell .file-actions {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Styles for the built-in action-cell buttons (favorite-star, kebab).
|
||||
* `.btn-action` is excluded — it owns its own colors via the generic
|
||||
* `.btn-action` rule + variant modifiers (e.g. `.btn-action--delete`). */
|
||||
@@ -639,6 +645,20 @@
|
||||
}
|
||||
|
||||
/* More actions button (three dots) — top-right of the thumbnail on a scrim. */
|
||||
/* Grid cards surface actions through the corner kebab (.file-actions) + the
|
||||
favorite star, both absolutely positioned below. The inline per-row action
|
||||
buttons (share/move/rename/delete) belong to the list view only — hide them
|
||||
here so they don't stack up along the bottom edge of the card. */
|
||||
.files-grid-view .file-item .action-cell .btn-action {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The favorite state is already shown by the corner star button, so the inline
|
||||
name-cell favorite badge is redundant on grid cards. */
|
||||
.files-grid-view .file-item .name-cell .item-badge {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.files-grid-view .file-item .file-actions {
|
||||
position: absolute;
|
||||
top: calc(var(--space-3) + 8px);
|
||||
@@ -0,0 +1,78 @@
|
||||
/* Upload Dropdown — ported from static/css/components/uploadDropdown.css.
|
||||
* Font Awesome `<i>` icons are emitted as `<svg class="oxi-icon">` by Icon.svelte,
|
||||
* so the icon selectors target `.oxi-icon` instead of `i`. */
|
||||
.upload-dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.upload-dropdown .btn-primary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1-5);
|
||||
}
|
||||
|
||||
.upload-dropdown-menu {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: calc(100% + 6px);
|
||||
left: 0;
|
||||
min-width: 200px;
|
||||
background: var(--color-bg-surface);
|
||||
border-radius: var(--radius-2xl);
|
||||
box-shadow: 0 8px 30px var(--color-shadow-md);
|
||||
border: 1px solid var(--color-border);
|
||||
z-index: 1000;
|
||||
overflow: hidden;
|
||||
animation: dropdownFadeIn 0.15s ease-out;
|
||||
}
|
||||
|
||||
@keyframes dropdownFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.upload-dropdown-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
width: 100%;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--color-text-dark);
|
||||
font-size: var(--text-base);
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.upload-dropdown-item:hover {
|
||||
background: var(--color-border-light);
|
||||
}
|
||||
|
||||
.upload-dropdown-item:active {
|
||||
background: var(--color-border);
|
||||
}
|
||||
|
||||
.upload-dropdown-item .oxi-icon {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
color: var(--color-text-subtle);
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.upload-dropdown-item:first-child {
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
}
|
||||
|
||||
.upload-caret {
|
||||
margin-left: var(--space-1);
|
||||
font-size: var(--text-xs);
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
/* User Menu */
|
||||
.user-menu-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.user-avatar-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
transition: transform var(--motion-base) var(--ease-standard);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Premium hover: ONE soft accent ring hugging the avatar + a gentle warm glow
|
||||
+ a subtle pop — replaces the old heavy double halo (button border ring with
|
||||
a gap + a second avatar ring). */
|
||||
.user-avatar-btn:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.user-avatar-btn:hover .user-vignette__avatar {
|
||||
box-shadow:
|
||||
0 0 0 3px var(--color-accent-ring),
|
||||
0 3px 12px -2px var(--color-accent-shadow);
|
||||
}
|
||||
|
||||
/* Menu open: a slightly firmer ring (same clean single-ring language). */
|
||||
.user-menu-wrapper.open .user-avatar-btn .user-vignette__avatar {
|
||||
box-shadow: 0 0 0 3px var(--color-accent-ring-strong);
|
||||
}
|
||||
|
||||
/* ── Avatar vignette overrides ────────────────────────────────────────────── */
|
||||
|
||||
/* The toolbar button and dropdown header mount avatar-only userVignette
|
||||
components. Sizing is owned by userVignette.css (--menu / --xl variants);
|
||||
the rules below add the decoration that is specific to this context. */
|
||||
|
||||
.user-avatar-btn .user-vignette__avatar {
|
||||
letter-spacing: 0.5px;
|
||||
user-select: none;
|
||||
/* Animate the ring/glow smoothly in AND out (transition on the base, not
|
||||
:hover). */
|
||||
transition: box-shadow var(--motion-base) var(--ease-standard);
|
||||
}
|
||||
|
||||
.user-menu-header .user-vignette__avatar {
|
||||
letter-spacing: 0.5px;
|
||||
box-shadow: 0 4px 12px var(--color-accent-shadow);
|
||||
}
|
||||
|
||||
.user-menu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 10px);
|
||||
right: 0;
|
||||
left: auto;
|
||||
width: 300px;
|
||||
background: var(--color-bg-surface);
|
||||
border-radius: var(--radius-3xl);
|
||||
box-shadow:
|
||||
0 12px 40px var(--color-shadow-md),
|
||||
0 0 0 1px var(--color-shadow-xs);
|
||||
z-index: 2000;
|
||||
overflow: hidden;
|
||||
animation: userMenuIn 0.2s ease-out;
|
||||
}
|
||||
|
||||
.user-menu-wrapper.open .user-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
[dir="rtl"] .user-menu {
|
||||
right: auto;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
@keyframes userMenuIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-8px) scale(0.97);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.user-menu-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3-5);
|
||||
padding: var(--space-5) var(--space-5) var(--space-4);
|
||||
background: var(--color-user-menu-header-bg);
|
||||
border-bottom: 1px solid var(--color-user-menu-header-border);
|
||||
}
|
||||
|
||||
/* The header vignette (xl, name + email) fills the available width. */
|
||||
.user-menu-header .user-vignette {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Increase name prominence relative to the base vignette style. */
|
||||
.user-menu-header .user-vignette__name {
|
||||
font-size: 15px;
|
||||
font-weight: var(--weight-semibold);
|
||||
color: var(--color-text-heading);
|
||||
}
|
||||
|
||||
.user-menu-header .user-vignette__email {
|
||||
font-size: 12.5px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.user-menu-storage {
|
||||
padding: var(--space-3-5) var(--space-5);
|
||||
}
|
||||
|
||||
.user-menu-storage-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: var(--weight-semibold);
|
||||
color: var(--color-text-subtle);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.user-menu-storage-label i {
|
||||
font-size: var(--text-2xs);
|
||||
color: var(--color-text-faint);
|
||||
}
|
||||
|
||||
.user-menu-storage-bar {
|
||||
height: 6px;
|
||||
background: var(--color-border-light);
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
margin-bottom: var(--space-1-5);
|
||||
}
|
||||
|
||||
.user-menu-storage-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--color-accent), var(--color-accent-second));
|
||||
border-radius: 3px;
|
||||
width: 0%;
|
||||
transition: width 0.5s ease;
|
||||
}
|
||||
|
||||
.user-menu-storage-text {
|
||||
font-size: 11.5px;
|
||||
color: var(--color-text-faint);
|
||||
}
|
||||
|
||||
.user-menu-divider {
|
||||
height: 1px;
|
||||
background: var(--color-border-light);
|
||||
margin: var(--space-1) 0;
|
||||
}
|
||||
|
||||
.user-menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
width: 100%;
|
||||
padding: var(--space-3) var(--space-5);
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--color-text-dark);
|
||||
font-size: var(--text-base);
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.user-menu-item:hover,
|
||||
.user-menu-item:focus-visible {
|
||||
background: var(--color-bg-hover);
|
||||
}
|
||||
|
||||
.user-menu-item i {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
color: var(--color-text-subtle);
|
||||
}
|
||||
|
||||
/* The appearance row is a plain container, not a button — the inner
|
||||
* segmented control captures the clicks. Match the height of other
|
||||
* .user-menu-item rows so the row reads as part of the same list. */
|
||||
.user-menu-item--theme {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.user-menu-item--theme:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Light / Like OS / Dark — three-option pill, active option highlighted
|
||||
* with the accent colour. Sits at the right edge of the row. */
|
||||
.theme-segmented {
|
||||
margin-left: auto;
|
||||
display: inline-flex;
|
||||
background: var(--color-bg-muted);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-full);
|
||||
padding: var(--space-0-5);
|
||||
gap: var(--space-0-5);
|
||||
}
|
||||
|
||||
.theme-segmented__opt {
|
||||
width: 28px;
|
||||
height: 22px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--color-text-subtle);
|
||||
border-radius: var(--radius-full);
|
||||
cursor: pointer;
|
||||
font-size: var(--text-2xs);
|
||||
padding: 0;
|
||||
transition:
|
||||
background 0.15s ease,
|
||||
color 0.15s ease;
|
||||
}
|
||||
|
||||
.theme-segmented__opt:hover {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.theme-segmented__opt--active {
|
||||
background: var(--color-accent);
|
||||
color: var(--color-danger-text);
|
||||
}
|
||||
|
||||
.theme-segmented__opt--active:hover {
|
||||
color: var(--color-danger-text);
|
||||
}
|
||||
|
||||
.user-menu-admin {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.user-menu-admin i {
|
||||
color: var(--color-info-blue);
|
||||
}
|
||||
|
||||
.user-menu-admin:hover {
|
||||
background: var(--color-info-bg-alt);
|
||||
}
|
||||
|
||||
.user-menu-role-badge {
|
||||
padding: 0 var(--space-5) var(--space-1);
|
||||
}
|
||||
|
||||
.role-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1);
|
||||
font-size: var(--text-2xs);
|
||||
font-weight: var(--weight-semibold);
|
||||
padding: var(--space-0-5) var(--space-2-5);
|
||||
border-radius: var(--radius-xl);
|
||||
}
|
||||
|
||||
.role-badge-admin {
|
||||
background: var(--color-info-surface);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.role-badge i {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.user-menu-logout {
|
||||
color: var(--color-danger-alt);
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
.user-menu-logout i {
|
||||
color: var(--color-danger-alt);
|
||||
}
|
||||
|
||||
.user-menu-logout:hover {
|
||||
background: var(--color-danger-lighter);
|
||||
}
|
||||
Reference in New Issue
Block a user