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

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