PluginProbe
The Innovative Form Builder – IvyForms / 0.3
The Innovative Form Builder – IvyForms v0.3
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.3, at frontend/src/views/_components/menu/IvyHeaderButton.vue

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