@necrolab/dashboard 0.5.13 → 0.5.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/plans/2026-02-08-tailwind-consolidation.md +330 -308
- package/package.json +1 -1
- package/src/assets/css/base/color-fallbacks.scss +10 -0
- package/src/assets/css/components/headers.scss +127 -0
- package/src/assets/css/components/search-groups.scss +3 -0
- package/src/assets/css/main.scss +8 -0
- package/src/components/Table/Table.vue +60 -5
- package/src/components/Tasks/Utilities.vue +4 -2
- package/src/components/ui/InfoRow.vue +3 -1
- package/src/components/ui/Modal.vue +33 -25
- package/src/components/ui/controls/atomic/Dropdown.vue +56 -13
- package/src/components/ui/controls/atomic/MultiDropdown.vue +28 -2
- package/src/composables/useDropdownPosition.js +2 -2
- package/src/views/Accounts.vue +4 -7
- package/src/views/Console.vue +6 -4
- package/src/views/Editor.vue +6 -4
- package/src/views/FilterBuilder.vue +4 -4
- package/src/views/Profiles.vue +4 -7
- package/src/views/Tasks.vue +7 -7
package/package.json
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
OKLCH COLOR FALLBACKS FOR CROSS-DEVICE CONSISTENCY
|
|
3
|
+
Note: iOS 26 Safari renders OKLCH in Display P3, causing color shifts
|
|
4
|
+
Currently no perfect fix - OKLCH support varies by device/gamut
|
|
5
|
+
========================================================================== */
|
|
6
|
+
|
|
7
|
+
/* Placeholder for future color space fixes */
|
|
8
|
+
:root {
|
|
9
|
+
color-scheme: dark;
|
|
10
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
PAGE HEADERS
|
|
3
|
+
Ultra-clean, consistent styling for all page headers
|
|
4
|
+
========================================================================== */
|
|
5
|
+
|
|
6
|
+
.page-header {
|
|
7
|
+
@apply flex items-center justify-between;
|
|
8
|
+
padding-top: 1.5rem;
|
|
9
|
+
padding-bottom: 0.5rem;
|
|
10
|
+
|
|
11
|
+
/* Header card container */
|
|
12
|
+
.page-header-card {
|
|
13
|
+
@apply flex items-center gap-2.5 rounded-lg;
|
|
14
|
+
padding: 0.375rem 0.75rem;
|
|
15
|
+
background: linear-gradient(135deg, oklch(0.22 0 0) 0%, oklch(0.24 0 0) 100%);
|
|
16
|
+
border: 1px solid oklch(0.28 0 0);
|
|
17
|
+
|
|
18
|
+
/* Icon - static by default */
|
|
19
|
+
svg, img {
|
|
20
|
+
width: 17px;
|
|
21
|
+
height: 17px;
|
|
22
|
+
color: oklch(0.85 0 0);
|
|
23
|
+
flex-shrink: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Clickable icon wrapper - only for Tasks page */
|
|
27
|
+
.icon-button {
|
|
28
|
+
@apply flex items-center justify-center rounded;
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
margin: -0.125rem 0;
|
|
31
|
+
padding: 0.125rem;
|
|
32
|
+
transition: background 0.2s ease;
|
|
33
|
+
|
|
34
|
+
svg, img {
|
|
35
|
+
width: 17px;
|
|
36
|
+
height: 17px;
|
|
37
|
+
color: oklch(0.85 0 0);
|
|
38
|
+
transition: transform 0.4s ease, color 0.2s ease;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&:hover {
|
|
42
|
+
background: oklch(0.26 0 0);
|
|
43
|
+
|
|
44
|
+
svg, img {
|
|
45
|
+
color: oklch(0.95 0 0);
|
|
46
|
+
transform: rotate(90deg);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&:active {
|
|
51
|
+
background: oklch(0.20 0 0);
|
|
52
|
+
|
|
53
|
+
svg, img {
|
|
54
|
+
transform: rotate(180deg);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Title text */
|
|
60
|
+
h4 {
|
|
61
|
+
@apply font-semibold;
|
|
62
|
+
font-size: 1rem;
|
|
63
|
+
line-height: 1.2;
|
|
64
|
+
color: oklch(0.95 0 0);
|
|
65
|
+
letter-spacing: -0.01em;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Count badge - only for Tasks page */
|
|
69
|
+
.page-header-count {
|
|
70
|
+
@apply inline-flex items-center justify-center rounded px-1.5 py-0.5 ml-1.5;
|
|
71
|
+
font-size: 0.6875rem;
|
|
72
|
+
font-weight: 600;
|
|
73
|
+
min-width: 20px;
|
|
74
|
+
background: oklch(0.20 0 0);
|
|
75
|
+
border: 1px solid oklch(0.26 0 0);
|
|
76
|
+
color: oklch(0.70 0 0);
|
|
77
|
+
letter-spacing: 0.01em;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Mobile responsive */
|
|
82
|
+
@media (max-width: 640px) {
|
|
83
|
+
padding-top: 1rem;
|
|
84
|
+
|
|
85
|
+
.page-header-card {
|
|
86
|
+
gap: 2.5;
|
|
87
|
+
padding: 0.5rem 0.875rem;
|
|
88
|
+
|
|
89
|
+
svg, img {
|
|
90
|
+
width: 18px;
|
|
91
|
+
height: 18px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
h4 {
|
|
95
|
+
font-size: 1rem;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.page-header-count {
|
|
99
|
+
font-size: 0.6875rem;
|
|
100
|
+
padding: 0.125rem 0.375rem;
|
|
101
|
+
min-width: 20px;
|
|
102
|
+
margin-left: 0.375rem;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* Tablet responsive */
|
|
108
|
+
@media (min-width: 641px) and (max-width: 1024px) {
|
|
109
|
+
.page-header-card {
|
|
110
|
+
svg, img {
|
|
111
|
+
width: 19px;
|
|
112
|
+
height: 19px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
h4 {
|
|
116
|
+
font-size: 1.0625rem;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* PWA mode adjustments */
|
|
123
|
+
@media (display-mode: standalone) {
|
|
124
|
+
.page-header {
|
|
125
|
+
padding-top: 3.5rem !important;
|
|
126
|
+
}
|
|
127
|
+
}
|
package/src/assets/css/main.scss
CHANGED
|
@@ -7,17 +7,25 @@
|
|
|
7
7
|
@use "base/reset";
|
|
8
8
|
@use "base/scroll";
|
|
9
9
|
@use "base/typography";
|
|
10
|
+
@use "base/color-fallbacks";
|
|
10
11
|
@use "components/buttons";
|
|
11
12
|
@use "components/forms";
|
|
12
13
|
@use "components/toasts";
|
|
13
14
|
@use "components/modals";
|
|
14
15
|
@use "components/tables";
|
|
15
16
|
@use "components/search-groups";
|
|
17
|
+
@use "components/headers";
|
|
16
18
|
|
|
17
19
|
/* ==========================================================================
|
|
18
20
|
BODY LAYOUT & BACKGROUND
|
|
19
21
|
========================================================================== */
|
|
20
22
|
|
|
23
|
+
html {
|
|
24
|
+
background-color: oklch(0.1822 0 0);
|
|
25
|
+
min-height: 100vh;
|
|
26
|
+
min-height: 100dvh;
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
body {
|
|
22
30
|
background-color: oklch(0.1822 0 0);
|
|
23
31
|
position: relative;
|
|
@@ -5,20 +5,75 @@
|
|
|
5
5
|
</template>
|
|
6
6
|
<style lang="scss">
|
|
7
7
|
.table-component {
|
|
8
|
-
@apply flex-col
|
|
9
|
-
@apply overflow-x-auto overflow-y-auto
|
|
8
|
+
@apply relative box-border flex flex-col rounded-lg border border-dark-600 bg-dark-500 bg-clip-padding;
|
|
9
|
+
@apply overflow-x-auto overflow-y-auto;
|
|
10
10
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
11
11
|
overscroll-behavior: auto;
|
|
12
|
-
max-height: calc(100vh -
|
|
12
|
+
max-height: calc(100vh - 300px);
|
|
13
13
|
-webkit-overflow-scrolling: touch;
|
|
14
|
+
touch-action: pan-x pan-y;
|
|
15
|
+
|
|
16
|
+
/* iPad Pro and larger tablets - more space for UTILS */
|
|
17
|
+
@media (min-width: 768px) and (max-width: 1440px) {
|
|
18
|
+
max-height: calc(100vh - 400px);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* iPad portrait - even more space needed */
|
|
22
|
+
@media (min-width: 768px) and (max-width: 1100px) and (orientation: portrait) {
|
|
23
|
+
max-height: calc(100vh - 450px);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* PWA mode - account for status bar and home indicator */
|
|
27
|
+
@media (display-mode: standalone) {
|
|
28
|
+
max-height: calc(100vh - 420px);
|
|
29
|
+
|
|
30
|
+
@media (min-width: 768px) and (max-width: 1440px) {
|
|
31
|
+
max-height: calc(100vh - 480px);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* iPad portrait PWA - maximum space for UTILS */
|
|
35
|
+
@media (min-width: 768px) and (max-width: 1100px) and (orientation: portrait) {
|
|
36
|
+
max-height: calc(100vh - 500px);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
14
39
|
}
|
|
15
40
|
|
|
16
|
-
.table-component > .grid {
|
|
17
|
-
@apply bg-dark-400;
|
|
41
|
+
.table-component > .grid:not(:first-child) {
|
|
18
42
|
border-bottom: 1px solid oklch(0.26 0 0);
|
|
19
43
|
// Only enforce min-width on desktop, allow mobile to fit screen
|
|
20
44
|
@media (min-width: 768px) {
|
|
21
45
|
min-width: 640px;
|
|
22
46
|
}
|
|
23
47
|
}
|
|
48
|
+
|
|
49
|
+
/* Remove border from last row */
|
|
50
|
+
.table-component > .grid:last-child {
|
|
51
|
+
border-bottom: none;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Odd rows (lighter) */
|
|
55
|
+
.table-component > .grid:nth-child(odd) {
|
|
56
|
+
@apply bg-dark-300;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Even rows (darker) */
|
|
60
|
+
.table-component > .grid:nth-child(even) {
|
|
61
|
+
@apply bg-dark-400;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* First grid child (header) keeps its own background */
|
|
65
|
+
.table-component > .grid:first-child {
|
|
66
|
+
border-bottom: 1px solid oklch(0.26 0 0);
|
|
67
|
+
@apply rounded-t-lg;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
@media (min-width: 768px) {
|
|
70
|
+
min-width: 640px;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Last row rounded bottom corners */
|
|
75
|
+
.table-component > .grid:last-child {
|
|
76
|
+
@apply rounded-b-lg;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
}
|
|
24
79
|
</style>
|
|
@@ -24,15 +24,17 @@ const ui = useUIStore();
|
|
|
24
24
|
</script>
|
|
25
25
|
<style lang="scss" scoped>
|
|
26
26
|
.utilities-wrapper {
|
|
27
|
+
margin-bottom: 2rem;
|
|
28
|
+
|
|
27
29
|
// Add extra margin on mobile to prevent buttons from being cut off
|
|
28
30
|
@media (max-width: 768px) {
|
|
29
31
|
margin-top: 1rem;
|
|
30
|
-
margin-bottom:
|
|
32
|
+
margin-bottom: 2.5rem;
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
.utility-btn {
|
|
35
|
-
height:
|
|
37
|
+
height: 42px;
|
|
36
38
|
|
|
37
39
|
@media (max-width: 768px) {
|
|
38
40
|
height: 40px;
|
|
@@ -78,7 +78,8 @@ const handleCopy = () => {
|
|
|
78
78
|
|
|
79
79
|
.info-value {
|
|
80
80
|
@apply text-sm flex-1 text-light-300;
|
|
81
|
-
@apply break-words;
|
|
81
|
+
@apply break-words overflow-hidden;
|
|
82
|
+
min-width: 0; // Allow flex item to shrink below content size
|
|
82
83
|
|
|
83
84
|
@media (max-width: 768px) {
|
|
84
85
|
@apply text-[13px];
|
|
@@ -90,6 +91,7 @@ const handleCopy = () => {
|
|
|
90
91
|
@apply w-8 h-8 rounded transition-all duration-150;
|
|
91
92
|
@apply bg-transparent text-light-500 hover:text-light-300 hover:bg-dark-600;
|
|
92
93
|
@apply flex-shrink-0;
|
|
94
|
+
@apply ml-2; // Ensure spacing from value
|
|
93
95
|
|
|
94
96
|
&.copied {
|
|
95
97
|
@apply text-accent-green;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="modal-mask fixed inset-0 z-modal bg-overlay-dark backdrop-blur-xs flex
|
|
3
|
-
<div class="component-modal
|
|
2
|
+
<div class="modal-mask fixed inset-0 z-modal bg-overlay-dark backdrop-blur-xs flex scrollable overflow-y-auto" role="dialog" @touchmove.stop>
|
|
3
|
+
<div class="component-modal" ref="target">
|
|
4
4
|
<div class="modal-header">
|
|
5
5
|
<slot name="header" />
|
|
6
6
|
<button @click="ui.toggleModal()" class="btn-icon border-none hover:bg-dark-400">
|
|
@@ -24,30 +24,16 @@ const target = ref(null);
|
|
|
24
24
|
|
|
25
25
|
// Store original body styles
|
|
26
26
|
let originalOverflow = "";
|
|
27
|
-
let originalPosition = "";
|
|
28
|
-
let originalTop = "";
|
|
29
|
-
let scrollY = 0;
|
|
30
27
|
|
|
31
28
|
onMounted(() => {
|
|
32
|
-
// Lock body scroll
|
|
33
|
-
scrollY = window.scrollY;
|
|
29
|
+
// Lock body scroll - simple overflow approach
|
|
34
30
|
originalOverflow = document.body.style.overflow;
|
|
35
|
-
originalPosition = document.body.style.position;
|
|
36
|
-
originalTop = document.body.style.top;
|
|
37
|
-
|
|
38
31
|
document.body.style.overflow = "hidden";
|
|
39
|
-
document.body.style.position = "fixed";
|
|
40
|
-
document.body.style.top = `-${scrollY}px`;
|
|
41
|
-
document.body.style.width = "100%";
|
|
42
32
|
});
|
|
43
33
|
|
|
44
34
|
onUnmounted(() => {
|
|
45
35
|
// Restore body scroll
|
|
46
|
-
document.body.style.overflow = originalOverflow;
|
|
47
|
-
document.body.style.position = originalPosition;
|
|
48
|
-
document.body.style.top = originalTop;
|
|
49
|
-
document.body.style.width = "";
|
|
50
|
-
window.scrollTo(0, scrollY);
|
|
36
|
+
document.body.style.overflow = originalOverflow || "";
|
|
51
37
|
});
|
|
52
38
|
|
|
53
39
|
onClickOutside(target, (event) => {
|
|
@@ -59,7 +45,7 @@ onClickOutside(target, (event) => {
|
|
|
59
45
|
@apply w-screen duration-300 ease-in-out;
|
|
60
46
|
align-items: flex-start;
|
|
61
47
|
justify-content: center;
|
|
62
|
-
padding: 1rem;
|
|
48
|
+
padding: 2rem 1rem 4rem 1rem !important; /* More bottom padding for scrollable space */
|
|
63
49
|
height: 100dvh;
|
|
64
50
|
overflow-y: auto;
|
|
65
51
|
-webkit-overflow-scrolling: touch;
|
|
@@ -89,17 +75,20 @@ onClickOutside(target, (event) => {
|
|
|
89
75
|
}
|
|
90
76
|
}
|
|
91
77
|
|
|
78
|
+
/* Desktop - extra bottom padding for scrollable space */
|
|
79
|
+
@media (min-width: 811px) {
|
|
80
|
+
.modal-mask {
|
|
81
|
+
padding: 2rem 1rem 6rem 1rem !important;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
92
85
|
@media (max-width: 810px) {
|
|
93
86
|
.modal-mask {
|
|
94
|
-
|
|
95
|
-
justify-content: center;
|
|
96
|
-
padding: 1rem;
|
|
97
|
-
padding-top: 3rem;
|
|
87
|
+
padding: 3rem 1rem !important; /* Mobile: more padding */
|
|
98
88
|
}
|
|
99
89
|
|
|
100
90
|
.component-modal {
|
|
101
91
|
width: calc(100vw - 2rem);
|
|
102
|
-
margin-bottom: 3rem;
|
|
103
92
|
}
|
|
104
93
|
|
|
105
94
|
.modal-body {
|
|
@@ -109,10 +98,29 @@ onClickOutside(target, (event) => {
|
|
|
109
98
|
}
|
|
110
99
|
}
|
|
111
100
|
|
|
112
|
-
/* iPhone portrait mode - extra spacing
|
|
101
|
+
/* iPhone portrait mode - extra bottom spacing */
|
|
113
102
|
@media (max-width: 480px) and (orientation: portrait) {
|
|
103
|
+
.modal-mask {
|
|
104
|
+
padding-bottom: 4rem !important;
|
|
105
|
+
}
|
|
106
|
+
|
|
114
107
|
.component-modal {
|
|
115
108
|
max-height: none;
|
|
116
109
|
}
|
|
117
110
|
}
|
|
111
|
+
|
|
112
|
+
/* PWA mode - extra spacing for iPhone status bar and home indicator */
|
|
113
|
+
@media (display-mode: standalone) {
|
|
114
|
+
.modal-mask {
|
|
115
|
+
padding-top: 3rem !important;
|
|
116
|
+
padding-bottom: 6rem !important;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@media (max-width: 810px) {
|
|
120
|
+
.modal-mask {
|
|
121
|
+
padding-top: 4rem !important;
|
|
122
|
+
padding-bottom: 5rem !important;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
118
126
|
</style>
|
|
@@ -13,19 +13,17 @@
|
|
|
13
13
|
class="dropdown-menu-portal scrollable"
|
|
14
14
|
:style="menuStyle"
|
|
15
15
|
@click.stop
|
|
16
|
-
@wheel.stop
|
|
17
|
-
@touchmove.stop>
|
|
16
|
+
@wheel.stop>
|
|
18
17
|
<button
|
|
19
18
|
v-bind:key="f"
|
|
20
19
|
class="dropdown-item"
|
|
21
20
|
:class="i !== 0 ? 'border-t border-dark-650' : ''"
|
|
22
21
|
v-for="(f, i) in !allowDefault ? props.options : ['', ...props.options]"
|
|
23
|
-
@
|
|
24
|
-
|
|
22
|
+
@click.prevent.stop="chose(f)">
|
|
23
|
+
<CheckmarkIcon v-if="(f || props.default) === currentValue" class="mr-2 flex-shrink-0" />
|
|
25
24
|
<span class="dropdown-item-text" :class="capitalize ? 'capitalize' : ''">
|
|
26
25
|
{{ f ? f : props.default }}
|
|
27
26
|
</span>
|
|
28
|
-
<CheckmarkIcon v-if="(f || props.default) === currentValue" class="ml-2" />
|
|
29
27
|
</button>
|
|
30
28
|
</div>
|
|
31
29
|
</transition>
|
|
@@ -68,11 +66,11 @@ const id = Math.random();
|
|
|
68
66
|
const opened = computed(() => ui.currentDropdown === id);
|
|
69
67
|
|
|
70
68
|
const { menuStyle, updatePosition } = useDropdownPosition(dropdownRef, {
|
|
71
|
-
maxHeight:
|
|
69
|
+
maxHeight: Math.floor(window.innerHeight * 0.85), // 85% of viewport
|
|
72
70
|
includeAdjacentButtons: props.includeAdjacentButtons,
|
|
73
71
|
estimateHeight: () => {
|
|
74
72
|
const optionsCount = !props.allowDefault ? props.options?.length || 0 : (props.options?.length || 0) + 1;
|
|
75
|
-
return Math.min(optionsCount * 44,
|
|
73
|
+
return Math.min(optionsCount * 44, Math.floor(window.innerHeight * 0.85));
|
|
76
74
|
}
|
|
77
75
|
});
|
|
78
76
|
|
|
@@ -104,6 +102,39 @@ const toggleOpened = () => {
|
|
|
104
102
|
} else {
|
|
105
103
|
ui.setCurrentDropdown(id);
|
|
106
104
|
updatePosition();
|
|
105
|
+
// Set all items to same width only if horizontal scrolling is needed
|
|
106
|
+
setTimeout(() => {
|
|
107
|
+
const portal = document.querySelector('.dropdown-menu-portal');
|
|
108
|
+
const items = portal?.querySelectorAll('.dropdown-item');
|
|
109
|
+
if (items && items.length > 0) {
|
|
110
|
+
let maxWidth = 0;
|
|
111
|
+
// Reset styles first to get accurate measurements
|
|
112
|
+
items.forEach(item => {
|
|
113
|
+
item.style.width = '';
|
|
114
|
+
item.style.minWidth = '';
|
|
115
|
+
});
|
|
116
|
+
portal.style.overflowX = '';
|
|
117
|
+
|
|
118
|
+
// Measure actual content width
|
|
119
|
+
items.forEach(item => {
|
|
120
|
+
const contentWidth = item.scrollWidth;
|
|
121
|
+
maxWidth = Math.max(maxWidth, contentWidth);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Only enable horizontal scrolling if content is truly wider than the max allowed width
|
|
125
|
+
const maxAllowedWidth = Math.min(400, window.innerWidth * 0.9);
|
|
126
|
+
if (maxWidth > maxAllowedWidth) {
|
|
127
|
+
// Enable horizontal scrolling for long items
|
|
128
|
+
portal.style.overflowX = 'auto';
|
|
129
|
+
items.forEach(item => {
|
|
130
|
+
item.style.minWidth = maxWidth + 'px';
|
|
131
|
+
});
|
|
132
|
+
} else {
|
|
133
|
+
// Normal display - no horizontal scrolling needed
|
|
134
|
+
portal.style.overflowX = 'hidden';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}, 50);
|
|
107
138
|
}
|
|
108
139
|
};
|
|
109
140
|
|
|
@@ -157,6 +188,7 @@ const chose = (f) => {
|
|
|
157
188
|
|
|
158
189
|
.dropdown-value {
|
|
159
190
|
@apply overflow-hidden truncate min-w-0 flex-1 mr-2 text-sm;
|
|
191
|
+
padding-right: 2rem; /* Extra space to prevent collision with arrow */
|
|
160
192
|
}
|
|
161
193
|
|
|
162
194
|
@media (min-width: 768px) {
|
|
@@ -177,17 +209,22 @@ const chose = (f) => {
|
|
|
177
209
|
}
|
|
178
210
|
|
|
179
211
|
.dropdown-menu-portal {
|
|
180
|
-
@apply rounded-xl shadow-2xl bg-dark-300 border border-dark-600
|
|
212
|
+
@apply rounded-xl shadow-2xl bg-dark-300 border border-dark-600;
|
|
181
213
|
backdrop-filter: blur(12px);
|
|
182
214
|
box-shadow: 0 20px 25px -5px oklch(0 0 0 / 0.4), 0 10px 10px -5px oklch(0 0 0 / 0.2),
|
|
183
215
|
0 0 0 1px oklch(1 0 0 / 0.05);
|
|
216
|
+
overflow-x: hidden;
|
|
217
|
+
overflow-y: auto;
|
|
184
218
|
overscroll-behavior: contain;
|
|
185
219
|
-webkit-overflow-scrolling: touch;
|
|
220
|
+
touch-action: pan-y;
|
|
186
221
|
scrollbar-width: thin;
|
|
187
222
|
scrollbar-color: oklch(0.35 0 0) oklch(0.19 0 0);
|
|
188
223
|
z-index: 1000;
|
|
189
224
|
min-width: 200px;
|
|
190
|
-
max-width: 90vw;
|
|
225
|
+
max-width: min(400px, 90vw);
|
|
226
|
+
display: flex;
|
|
227
|
+
flex-direction: column;
|
|
191
228
|
}
|
|
192
229
|
|
|
193
230
|
.dropdown-menu-portal::-webkit-scrollbar {
|
|
@@ -209,11 +246,16 @@ const chose = (f) => {
|
|
|
209
246
|
}
|
|
210
247
|
|
|
211
248
|
.dropdown-item {
|
|
212
|
-
@apply cursor-pointer text-left
|
|
249
|
+
@apply cursor-pointer text-left text-white transition-all duration-200;
|
|
213
250
|
padding: 0.75rem 1rem;
|
|
214
251
|
font-size: 0.875rem;
|
|
215
252
|
font-weight: 500;
|
|
216
253
|
border-bottom: 1px solid rgba(61, 62, 68, 0.3);
|
|
254
|
+
display: flex !important;
|
|
255
|
+
align-items: center;
|
|
256
|
+
gap: 1rem;
|
|
257
|
+
width: 100%;
|
|
258
|
+
flex-shrink: 0;
|
|
217
259
|
}
|
|
218
260
|
|
|
219
261
|
.dropdown-item:last-child {
|
|
@@ -221,7 +263,7 @@ const chose = (f) => {
|
|
|
221
263
|
}
|
|
222
264
|
|
|
223
265
|
.dropdown-item:hover {
|
|
224
|
-
|
|
266
|
+
background: oklch(0.2809 0 0) !important; /* Full width background */
|
|
225
267
|
color: oklch(1 0 0);
|
|
226
268
|
}
|
|
227
269
|
|
|
@@ -244,9 +286,10 @@ const chose = (f) => {
|
|
|
244
286
|
}
|
|
245
287
|
|
|
246
288
|
.dropdown-item-text {
|
|
247
|
-
@apply pr-2;
|
|
289
|
+
@apply pr-2 flex-1;
|
|
248
290
|
white-space: nowrap;
|
|
249
|
-
overflow:
|
|
291
|
+
overflow: hidden;
|
|
292
|
+
text-overflow: ellipsis;
|
|
250
293
|
}
|
|
251
294
|
|
|
252
295
|
.dropdown-item svg {
|
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
class="dropdown-menu-portal multi scrollable"
|
|
19
19
|
:style="menuStyle"
|
|
20
20
|
@click.stop
|
|
21
|
-
@wheel.stop
|
|
22
|
-
@touchmove.stop>
|
|
21
|
+
@wheel.stop>
|
|
23
22
|
<div class="option-list scrollable">
|
|
24
23
|
<button
|
|
25
24
|
v-for="(option, i) in props.options"
|
|
@@ -133,6 +132,33 @@ const toggleOpened = () => {
|
|
|
133
132
|
} else {
|
|
134
133
|
ui.setCurrentDropdown(id);
|
|
135
134
|
updatePosition();
|
|
135
|
+
// Set all items to same width only if horizontal scrolling is needed
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
const portal = document.querySelector('.dropdown-menu-portal');
|
|
138
|
+
const items = portal?.querySelectorAll('.dropdown-item');
|
|
139
|
+
if (items && items.length > 0) {
|
|
140
|
+
let maxWidth = 0;
|
|
141
|
+
items.forEach(item => {
|
|
142
|
+
item.style.width = 'max-content';
|
|
143
|
+
maxWidth = Math.max(maxWidth, item.scrollWidth);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Only set explicit widths if content is wider than container
|
|
147
|
+
if (maxWidth > portal.offsetWidth) {
|
|
148
|
+
// Enable horizontal scrolling for long items
|
|
149
|
+
portal.style.overflowX = 'auto';
|
|
150
|
+
items.forEach(item => {
|
|
151
|
+
item.style.width = maxWidth + 'px';
|
|
152
|
+
});
|
|
153
|
+
} else {
|
|
154
|
+
// Disable horizontal scrolling for short items
|
|
155
|
+
portal.style.overflowX = 'hidden';
|
|
156
|
+
items.forEach(item => {
|
|
157
|
+
item.style.width = '100%';
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}, 50);
|
|
136
162
|
}
|
|
137
163
|
};
|
|
138
164
|
|
|
@@ -6,7 +6,7 @@ export function useDropdownPosition(dropdownRef, options = {}) {
|
|
|
6
6
|
offset = { x: -1, y: 4 },
|
|
7
7
|
zIndex = 50000,
|
|
8
8
|
minWidth = null,
|
|
9
|
-
maxHeight =
|
|
9
|
+
maxHeight = window.innerHeight * 0.8, // Use 80% of viewport height
|
|
10
10
|
estimateHeight = null,
|
|
11
11
|
includeAdjacentButtons = false,
|
|
12
12
|
containerSelector = null
|
|
@@ -24,7 +24,7 @@ export function useDropdownPosition(dropdownRef, options = {}) {
|
|
|
24
24
|
const menuHeight = estimateHeight ? estimateHeight() : maxHeight;
|
|
25
25
|
|
|
26
26
|
// Calculate width including adjacent buttons if specified
|
|
27
|
-
let menuWidth = minWidth || rect.width
|
|
27
|
+
let menuWidth = minWidth || rect.width;
|
|
28
28
|
|
|
29
29
|
if (includeAdjacentButtons) {
|
|
30
30
|
// Look for parent container with buttons
|
package/src/views/Accounts.vue
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<div class="
|
|
4
|
-
<div class="
|
|
5
|
-
<MailIcon
|
|
6
|
-
<h4
|
|
7
|
-
Accounts
|
|
8
|
-
<span class="text-sm font-medium text-light-400 pl-1">{{ ui.getSelectedAccounts().length }}</span>
|
|
9
|
-
</h4>
|
|
3
|
+
<div class="page-header">
|
|
4
|
+
<div class="page-header-card">
|
|
5
|
+
<MailIcon />
|
|
6
|
+
<h4>Accounts</h4>
|
|
10
7
|
</div>
|
|
11
8
|
<ul class="mobile-icons">
|
|
12
9
|
<li>
|
package/src/views/Console.vue
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="console-page">
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
<div class="page-header" style="padding-bottom: 0.75rem;">
|
|
4
|
+
<div class="page-header-card">
|
|
5
|
+
<ConsoleIcon />
|
|
6
|
+
<h4>Console</h4>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
7
9
|
|
|
8
10
|
<div>
|
|
9
11
|
<div class="mb-3 flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
package/src/views/Editor.vue
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
3
|
<!-- Heading -->
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
<div class="page-header" style="padding-bottom: 1.25rem;">
|
|
5
|
+
<div class="page-header-card">
|
|
6
|
+
<img src="@/assets/img/pencil.svg" />
|
|
7
|
+
<h4>Editor</h4>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
8
10
|
|
|
9
11
|
<div class="bg-dark-400 border border-dark-650 rounded shadow-sm p-2">
|
|
10
12
|
<!-- Admin Editor Section - Hidden when proxy editor is open -->
|