PluginProbe
The Innovative Form Builder – IvyForms / 0.2
The Innovative Form Builder – IvyForms v0.2
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / frontend / src / views / _components / menu / IvyHeaderButton.vue

IvyHeaderButton.vue in The Innovative Form Builder – IvyForms 0.2, at frontend/src/views/_components/menu/IvyHeaderButton.vue

304 lines 6.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <template>
2 <div class="ivyforms-header-button-wrapper">
3 <ElMenuItem
4 :index="name"
5 :class="[
6 `size-${size}`,
7 'ivyforms-menu-item',
8 `priority-${priority}`,
9 `type-${type}`,
10 { 'is-active-item': isActive },
11 { 'has-coming-soon': comingSoon },
12 ]"
13 :disabled="disabled || comingSoon"
14 :aria-label="props.ariaLabel || getLabel('header_button')"
15 tabindex="0"
16 @click="onClick"
17 >
18 <IvyIcon v-if="iconStart?.name" v-bind="iconStart" />
19
20 <span>
21 {{ label }}
22 </span>
23
24 <IvyIcon v-if="iconEnd?.name" v-bind="iconEnd" />
25 </ElMenuItem>
26
27 <ComingSoonBadge
28 v-if="props.comingSoon"
29 class="ivyforms-header-button-wrapper__coming-soon"
30 :size="'s'"
31 />
32 </div>
33 </template>
34
35 <script setup lang="ts">
36 import { computed } from 'vue'
37 import type { IconCategory } from '@/types/icons/icon-category'
38 import type { IconType } from '@/types/icons/icon-type'
39 import { useLabels } from '@/composables/useLabels'
40 const { getLabel } = useLabels()
41
42 interface IconConfig {
43 name: string
44 type?: IconType
45 category?: IconCategory
46 size?: 'l' | 'd' | 's' | 'xs'
47 outerSize?: string
48 }
49
50 interface Props {
51 name?: string
52 label: string
53 priority?: 'primary' | 'secondary' | 'tertiary'
54 size?: 's' | 'd' | 'l'
55 type?: 'filled' | 'tonal' | 'white'
56 disabled?: boolean
57 isActive?: boolean
58 iconStartConfig?: IconConfig
59 iconEndConfig?: IconConfig
60 comingSoon?: boolean
61 ariaLabel?: string
62 }
63
64 // Default icon configuration
65 const defaultIconConfig: IconConfig = {
66 name: 'page',
67 size: 'l',
68 outerSize: '20px',
69 }
70
71 // Merge icon configuration only if the prop is passed
72 const getIconConfig = (iconConfig?: IconConfig) =>
73 iconConfig ? { ...defaultIconConfig, ...iconConfig } : undefined
74
75 const props = withDefaults(defineProps<Props>(), {
76 priority: 'primary',
77 size: 'd',
78 type: 'filled',
79 isActive: false,
80 disabled: false,
81 iconStartConfig: undefined,
82 iconEndConfig: undefined,
83 name: '',
84 comingSoon: false,
85 ariaLabel: '',
86 })
87
88 // Apply defaults only if the config exists
89 const iconStart = computed(() => getIconConfig(props.iconStartConfig))
90 const iconEnd = computed(() => getIconConfig(props.iconEndConfig))
91
92 const emit = defineEmits(['click'])
93
94 const onClick = () => {
95 if (!props.disabled) {
96 emit('click', props.name)
97 }
98 }
99 </script>
100
101 <style lang="scss">
102 @use 'sass:list' as *;
103 @use 'sass:meta' as *;
104
105 .ivyforms-header-button-wrapper {
106 justify-content: flex-start;
107 position: relative;
108 width: 100%;
109
110 &__coming-soon {
111 position: absolute;
112 top: -7px;
113 right: -4px;
114 }
115 }
116
117 .ivyforms-menu {
118 &.el-menu {
119 // Menu Item
120 .ivyforms-menu-item {
121 display: inline-flex;
122 align-items: center;
123 justify-content: center;
124 padding: 10px var(--spacing-04, 16px);
125 border-radius: 8px;
126 border: none;
127 min-width: 44px;
128 height: 40px;
129 //flex-shrink: 0;
130 transition: background-color 0.3s;
131 font-size: 14px;
132 margin: 0;
133 font-style: normal;
134 font-weight: 500;
135 gap: var(--spacing-01, 4px);
136 flex: 1;
137
138 // Define priorities and their styles
139 $priorities: (
140 'primary': (
141 transparent,
142 var(--map-base-text-0),
143 var(--map-base-brand-o05),
144 var(--map-base-brand-symbol-0),
145 var(--map-base-brand-fill-0),
146 $primitive-white,
147 ),
148 'secondary': (
149 transparent,
150 var(--map-base-text-0),
151 var(--map-base-purple-o05),
152 var(--map-base-purple-symbol-0),
153 var(--map-base-purple-fill-0),
154 $primitive-white,
155 ),
156 'tertiary': (
157 transparent,
158 var(--map-base-text-0),
159 var(--map-base-dusk-o10),
160 var(--map-base-text-0),
161 var(--map-base-dusk-o10),
162 var(--map-base-text-0),
163 ),
164 );
165
166 // Mixin for priority styles
167 @mixin menuStyles($priority, $colors: ()) {
168 $default-bg: nth($colors, 1);
169 $default-text: nth($colors, 2);
170 $hover-bg: nth($colors, 3);
171 $hover-text: nth($colors, 4);
172 $active-bg: nth($colors, 5);
173 $active-text: nth($colors, 6);
174
175 &.priority-#{$priority} {
176 background-color: $default-bg;
177 color: $default-text;
178
179 // Icon
180 .ivyforms-icon {
181 display: contents;
182 fill: $default-text;
183 width: 20px !important;
184 height: 20px;
185 svg {
186 transform: scale(0.67);
187 }
188 }
189
190 // Hover
191 &:hover,
192 &.is-hover {
193 background-color: $hover-bg;
194 color: $hover-text;
195
196 .ivyforms-icon {
197 fill: $hover-text;
198 }
199 }
200
201 // Active
202 &:active,
203 &.is-active-item {
204 border: none;
205 background-color: $active-bg;
206 color: $active-text !important;
207
208 .ivyforms-icon {
209 fill: $active-text;
210 }
211 }
212
213 // Focus
214 // Hover
215 &:focus,
216 &.is-focus {
217 background-color: $hover-bg;
218 color: $hover-text;
219
220 .ivyforms-icon {
221 fill: $hover-text;
222 }
223 }
224
225 // Default state when not active
226 &:not(.is-active-item) {
227 background-color: $default-bg;
228 color: $default-text;
229
230 .ivyforms-icon {
231 fill: $default-text;
232 }
233 }
234
235 &.type-tonal {
236 &:active,
237 &.is-active-item {
238 background-color: $hover-bg;
239 color: $hover-text !important;
240
241 .ivyforms-icon {
242 fill: $hover-text;
243 }
244 }
245 }
246
247 &.is-disabled {
248 &:active,
249 &.is-active-item {
250 color: $default-text !important;
251 }
252
253 &:hover,
254 &.is-hover,
255 &:focus,
256 &.is-focus {
257 background-color: $default-bg !important;
258 color: $default-text !important;
259 }
260 }
261
262 &.has-coming-soon {
263 margin: 0;
264 }
265 }
266
267 &.priority-tertiary {
268 &.is-active-item,
269 &:active {
270 border-radius: var(--radius-l, 8px);
271 background: var(--map-ground-level-3);
272 box-shadow: 0 4 15 0 rgba(0, 0, 0, 0.05);
273 }
274 }
275 }
276
277 // Generate styles for all priorities
278 @each $priority, $colors in $priorities {
279 @include menuStyles($priority, $colors);
280 }
281
282 // Size specific styles
283 &.size-s {
284 height: 32px;
285 max-height: 32px;
286 }
287
288 &.size-d {
289 height: 40px;
290 max-height: 40px;
291 }
292
293 &.size-l {
294 height: 48px;
295 max-height: 48px;
296 }
297 span {
298 line-height: 20px;
299 }
300 }
301 }
302 }
303 </style>
304