@imaginario27/air-ui-ds 1.0.16 → 1.0.17
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/components/layouts/Footer.vue +104 -0
- package/components/layouts/Heading.vue +36 -7
- package/components/layouts/Overtitle.vue +28 -2
- package/components/layouts/headers/ContentPageHeader.vue +0 -1
- package/models/enums/headings.ts +2 -0
- package/models/types/navigation.ts +4 -3
- package/package.json +1 -1
- package/components/layouts/ContainerWrapper.vue +0 -13
- package/components/layouts/headers/WebAppHeader.vue +0 -54
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<footer
|
|
3
|
+
:class="[
|
|
4
|
+
'w-full',
|
|
5
|
+
'bg-background-surface',
|
|
6
|
+
'py-section-xs',
|
|
7
|
+
hasSidePadding && 'px-content-side-padding-mobile md:px-content-side-padding',
|
|
8
|
+
]"
|
|
9
|
+
>
|
|
10
|
+
<MaxWidthContainer
|
|
11
|
+
:class="[!hasContentMaxWidth && '!max-w-full']"
|
|
12
|
+
>
|
|
13
|
+
<template v-if="!$slots['default']">
|
|
14
|
+
<div
|
|
15
|
+
:class="[
|
|
16
|
+
'w-full',
|
|
17
|
+
'flex',
|
|
18
|
+
'flex-col',
|
|
19
|
+
isMobileCentered &&'items-center text-center',
|
|
20
|
+
'gap-10',
|
|
21
|
+
'lg:flex-row',
|
|
22
|
+
'lg:items-start',
|
|
23
|
+
'lg:text-left',
|
|
24
|
+
'lg:justify-between',
|
|
25
|
+
]"
|
|
26
|
+
>
|
|
27
|
+
<span class="text-sm text-text-neutral-subtle">
|
|
28
|
+
{{ credits }}
|
|
29
|
+
</span>
|
|
30
|
+
|
|
31
|
+
<nav v-if="menuItems?.length">
|
|
32
|
+
<ul class="flex flex-col lg:flex-row gap-5">
|
|
33
|
+
<li
|
|
34
|
+
v-for="(item, index) in menuItems"
|
|
35
|
+
:key="index"
|
|
36
|
+
>
|
|
37
|
+
<NuxtLink
|
|
38
|
+
:to="item.to"
|
|
39
|
+
:class="[
|
|
40
|
+
'text-sm',
|
|
41
|
+
'hover:text-text-primary-brand-hover',
|
|
42
|
+
'transition-colors',
|
|
43
|
+
]"
|
|
44
|
+
>
|
|
45
|
+
{{ item.text }}
|
|
46
|
+
</NuxtLink>
|
|
47
|
+
</li>
|
|
48
|
+
</ul>
|
|
49
|
+
</nav>
|
|
50
|
+
|
|
51
|
+
<div v-if="socialNetworks?.length" class="flex gap-5">
|
|
52
|
+
<a
|
|
53
|
+
v-for="(network, index) in socialNetworks"
|
|
54
|
+
:key="index"
|
|
55
|
+
:href="network.link"
|
|
56
|
+
target="_blank"
|
|
57
|
+
rel="noopener noreferrer"
|
|
58
|
+
:class="[
|
|
59
|
+
'text-text-neutral-subtle',
|
|
60
|
+
'hover:text-text-primary-brand-hover',
|
|
61
|
+
'transition-colors',
|
|
62
|
+
]"
|
|
63
|
+
:aria-label="network.name"
|
|
64
|
+
>
|
|
65
|
+
<img
|
|
66
|
+
:src="network.icon"
|
|
67
|
+
:alt="`${network.name} icon`"
|
|
68
|
+
width="20"
|
|
69
|
+
height="20"
|
|
70
|
+
class="min-w-[20px] min-h-[20px]"
|
|
71
|
+
/>
|
|
72
|
+
</a>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</template>
|
|
76
|
+
<template v-else>
|
|
77
|
+
<slot />
|
|
78
|
+
</template>
|
|
79
|
+
</MaxWidthContainer>
|
|
80
|
+
</footer>
|
|
81
|
+
</template>
|
|
82
|
+
<script setup lang="ts">
|
|
83
|
+
// Props
|
|
84
|
+
defineProps({
|
|
85
|
+
credits: {
|
|
86
|
+
type: String as PropType<string>,
|
|
87
|
+
default: '© <year> <your-company>. All rights reserved.',
|
|
88
|
+
},
|
|
89
|
+
menuItems: Array as PropType<MenuItem[]>,
|
|
90
|
+
socialNetworks: Array as PropType<SocialNetwork[]>,
|
|
91
|
+
hasContentMaxWidth: {
|
|
92
|
+
type: Boolean as PropType<boolean>,
|
|
93
|
+
default: false,
|
|
94
|
+
},
|
|
95
|
+
hasSidePadding: {
|
|
96
|
+
type: Boolean as PropType<boolean>,
|
|
97
|
+
default: true,
|
|
98
|
+
},
|
|
99
|
+
isMobileCentered: {
|
|
100
|
+
type: Boolean as PropType<boolean>,
|
|
101
|
+
default: false,
|
|
102
|
+
},
|
|
103
|
+
})
|
|
104
|
+
</script>
|
|
@@ -3,26 +3,32 @@
|
|
|
3
3
|
:class="[
|
|
4
4
|
'w-full flex flex-col',
|
|
5
5
|
alignmentClasses,
|
|
6
|
-
titleClass,
|
|
7
6
|
]"
|
|
8
7
|
>
|
|
9
8
|
<!-- Overtitle -->
|
|
10
|
-
<
|
|
9
|
+
<span
|
|
11
10
|
v-if="overtitle"
|
|
12
11
|
:class="[
|
|
13
12
|
'font-semibold',
|
|
14
13
|
overtitleSizeClass,
|
|
15
14
|
'text-text-secondary-brand-default',
|
|
16
15
|
spaceOvertitleClass,
|
|
16
|
+
isOverTitleUppercase && 'uppercase',
|
|
17
|
+
overtitleClass,
|
|
17
18
|
]"
|
|
18
19
|
>
|
|
19
20
|
{{ overtitle }}
|
|
20
|
-
</
|
|
21
|
+
</span>
|
|
21
22
|
|
|
22
23
|
<!-- Dynamic title -->
|
|
23
24
|
<component
|
|
24
25
|
:is="headingTag"
|
|
25
|
-
:class="[
|
|
26
|
+
:class="[
|
|
27
|
+
titleSizeClass,
|
|
28
|
+
'font-semibold',
|
|
29
|
+
'text-text-default',
|
|
30
|
+
titleClass,
|
|
31
|
+
]"
|
|
26
32
|
>
|
|
27
33
|
{{ title }}
|
|
28
34
|
</component>
|
|
@@ -30,7 +36,12 @@
|
|
|
30
36
|
<!-- Description -->
|
|
31
37
|
<p
|
|
32
38
|
v-if="description"
|
|
33
|
-
:class="[
|
|
39
|
+
:class="[
|
|
40
|
+
descriptionSizeClass,
|
|
41
|
+
'text-text-neutral-subtle',
|
|
42
|
+
spaceDescriptionClass,
|
|
43
|
+
descriptionClass,
|
|
44
|
+
]"
|
|
34
45
|
>
|
|
35
46
|
{{ description }}
|
|
36
47
|
</p>
|
|
@@ -41,6 +52,10 @@
|
|
|
41
52
|
// Props
|
|
42
53
|
const props = defineProps({
|
|
43
54
|
overtitle: String as PropType<string>,
|
|
55
|
+
isOverTitleUppercase: {
|
|
56
|
+
type: Boolean as PropType<boolean>,
|
|
57
|
+
default: false,
|
|
58
|
+
},
|
|
44
59
|
title: {
|
|
45
60
|
type: String as PropType<string>,
|
|
46
61
|
default: 'Heading title'
|
|
@@ -64,15 +79,17 @@ const props = defineProps({
|
|
|
64
79
|
Object.values(HeadingSpacing).includes(value as HeadingSpacing),
|
|
65
80
|
},
|
|
66
81
|
headingTag: {
|
|
67
|
-
type: [String, Number] as PropType<'h1' | 'h2' | 'h3'>,
|
|
82
|
+
type: [String, Number] as PropType<'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'>,
|
|
68
83
|
default: 'h1',
|
|
69
|
-
validator: (value: string | number) => ['h1', 'h2', 'h3'].includes(value as string)
|
|
84
|
+
validator: (value: string | number) => ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(value as string)
|
|
70
85
|
},
|
|
71
86
|
isMobileCentered: {
|
|
72
87
|
type: Boolean as PropType<boolean>,
|
|
73
88
|
default: false,
|
|
74
89
|
},
|
|
90
|
+
overtitleClass: String as PropType<string>,
|
|
75
91
|
titleClass: String as PropType<string>,
|
|
92
|
+
descriptionClass: String as PropType<string>,
|
|
76
93
|
})
|
|
77
94
|
|
|
78
95
|
// Computed classes
|
|
@@ -100,6 +117,8 @@ const alignmentClasses = computed(() => {
|
|
|
100
117
|
|
|
101
118
|
const titleSizeClass = computed(() => {
|
|
102
119
|
const map = {
|
|
120
|
+
[HeadingSize.XXS]: 'text-lg',
|
|
121
|
+
[HeadingSize.XS]: 'text-xl',
|
|
103
122
|
[HeadingSize.SM]: 'text-2xl',
|
|
104
123
|
[HeadingSize.MD]: 'text-3xl md:text-4xl',
|
|
105
124
|
[HeadingSize.LG]: 'text-4xl md:text-5xl',
|
|
@@ -110,6 +129,8 @@ const titleSizeClass = computed(() => {
|
|
|
110
129
|
|
|
111
130
|
const overtitleSizeClass = computed(() => {
|
|
112
131
|
const map = {
|
|
132
|
+
[HeadingSize.XXS]: 'text-xs',
|
|
133
|
+
[HeadingSize.XS]: 'text-sm',
|
|
113
134
|
[HeadingSize.SM]: 'text-sm',
|
|
114
135
|
[HeadingSize.MD]: 'text-base',
|
|
115
136
|
[HeadingSize.LG]: 'text-base',
|
|
@@ -120,6 +141,8 @@ const overtitleSizeClass = computed(() => {
|
|
|
120
141
|
|
|
121
142
|
const descriptionSizeClass = computed(() => {
|
|
122
143
|
const map = {
|
|
144
|
+
[HeadingSize.XXS]: 'text-sm',
|
|
145
|
+
[HeadingSize.XS]: 'text-sm',
|
|
123
146
|
[HeadingSize.SM]: 'text-sm',
|
|
124
147
|
[HeadingSize.MD]: 'text-lg',
|
|
125
148
|
[HeadingSize.LG]: 'text-lg',
|
|
@@ -130,6 +153,8 @@ const descriptionSizeClass = computed(() => {
|
|
|
130
153
|
|
|
131
154
|
const spaceOvertitleClass = computed(() => {
|
|
132
155
|
const map = {
|
|
156
|
+
[HeadingSize.XXS]: 'mb-1',
|
|
157
|
+
[HeadingSize.XS]: 'mb-1',
|
|
133
158
|
[HeadingSize.SM]: 'mb-1',
|
|
134
159
|
[HeadingSize.MD]: 'mb-3',
|
|
135
160
|
[HeadingSize.LG]: 'mb-3',
|
|
@@ -140,12 +165,16 @@ const spaceOvertitleClass = computed(() => {
|
|
|
140
165
|
|
|
141
166
|
const spaceDescriptionClass = computed(() => {
|
|
142
167
|
const normal = {
|
|
168
|
+
[HeadingSize.XXS]: 'mt-3',
|
|
169
|
+
[HeadingSize.XS]: 'mt-3',
|
|
143
170
|
[HeadingSize.SM]: 'mt-3',
|
|
144
171
|
[HeadingSize.MD]: 'mt-4',
|
|
145
172
|
[HeadingSize.LG]: 'mt-6',
|
|
146
173
|
[HeadingSize.XL]: 'mt-4',
|
|
147
174
|
}
|
|
148
175
|
const spaced = {
|
|
176
|
+
[HeadingSize.XXS]: 'mt-4',
|
|
177
|
+
[HeadingSize.XS]: 'mt-4',
|
|
149
178
|
[HeadingSize.SM]: 'mt-4',
|
|
150
179
|
[HeadingSize.MD]: 'mt-5',
|
|
151
180
|
[HeadingSize.LG]: 'mt-9',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<span
|
|
3
3
|
:class="[
|
|
4
|
-
|
|
4
|
+
colorClass,
|
|
5
5
|
'text-sm',
|
|
6
6
|
'font-medium',
|
|
7
7
|
isUppercase && 'uppercase',
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
</template>
|
|
13
13
|
<script setup lang="ts">
|
|
14
14
|
// Props
|
|
15
|
-
defineProps({
|
|
15
|
+
const props = defineProps({
|
|
16
16
|
title: {
|
|
17
17
|
type: String as PropType<string>,
|
|
18
18
|
default: 'Overtitle'
|
|
@@ -20,6 +20,32 @@ defineProps({
|
|
|
20
20
|
isUppercase: {
|
|
21
21
|
type: Boolean as PropType<boolean>,
|
|
22
22
|
default: true,
|
|
23
|
+
},
|
|
24
|
+
color: {
|
|
25
|
+
type: String as PropType<
|
|
26
|
+
ColorAccent.PRIMARY_BRAND
|
|
27
|
+
| ColorAccent.SECONDARY_BRAND
|
|
28
|
+
| ColorAccent.NEUTRAL
|
|
29
|
+
>,
|
|
30
|
+
default: ColorAccent.SECONDARY_BRAND,
|
|
31
|
+
validator: (value: unknown): value is ColorAccent => {
|
|
32
|
+
return typeof value === 'string' &&
|
|
33
|
+
[
|
|
34
|
+
ColorAccent.PRIMARY_BRAND,
|
|
35
|
+
ColorAccent.SECONDARY_BRAND,
|
|
36
|
+
ColorAccent.NEUTRAL,
|
|
37
|
+
].includes(value as ColorAccent)
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const colorClass = computed(() => {
|
|
43
|
+
const variant: Partial<Record<ColorAccent, string>> = {
|
|
44
|
+
[ColorAccent.NEUTRAL]: 'text-text-default',
|
|
45
|
+
[ColorAccent.PRIMARY_BRAND]: 'text-text-primary-brand-default',
|
|
46
|
+
[ColorAccent.SECONDARY_BRAND]: 'text-text-secondary-brand-default',
|
|
23
47
|
}
|
|
48
|
+
|
|
49
|
+
return variant[props.color as ColorAccent] || 'text-text-secondary-brand-default'
|
|
24
50
|
})
|
|
25
51
|
</script>
|
package/models/enums/headings.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<header
|
|
3
|
-
:class="[
|
|
4
|
-
'flex',
|
|
5
|
-
'items-center',
|
|
6
|
-
'justify-between',
|
|
7
|
-
'pt-12',
|
|
8
|
-
'pb-8',
|
|
9
|
-
'gap-3',
|
|
10
|
-
'px-content-side-padding-mobile md:px-content-side-padding',
|
|
11
|
-
]"
|
|
12
|
-
>
|
|
13
|
-
<div class="flex gap-4">
|
|
14
|
-
<ActionIconButton
|
|
15
|
-
:icon="isMobileSidebarOpen ? 'mdiMenuOpen' : 'mdiMenuClose'"
|
|
16
|
-
class="lg:hidden shadow-sm"
|
|
17
|
-
@click="toggleMobileSidebar"
|
|
18
|
-
/>
|
|
19
|
-
<PageTitle class="hidden lg:flex" :type="pageTitleType"/>
|
|
20
|
-
</div>
|
|
21
|
-
<div class="flex gap-3 items-center xs:w-auto">
|
|
22
|
-
<slot name="header-actions" />
|
|
23
|
-
</div>
|
|
24
|
-
</header>
|
|
25
|
-
|
|
26
|
-
</template>
|
|
27
|
-
|
|
28
|
-
<script setup lang="ts">
|
|
29
|
-
// Imports
|
|
30
|
-
import { useRoute } from 'vue-router'
|
|
31
|
-
|
|
32
|
-
// Props
|
|
33
|
-
defineProps({
|
|
34
|
-
pageTitleType: {
|
|
35
|
-
type: String as PropType<PageTitleType>,
|
|
36
|
-
default: PageTitleType.SIMPLE
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
// Page title
|
|
41
|
-
const route = useRoute()
|
|
42
|
-
const currentPageTitle = computed<string>(() =>
|
|
43
|
-
(route.meta.title as string) || 'Page title'
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
// Dynamically set the page title
|
|
47
|
-
useHead(() => ({
|
|
48
|
-
title: pageTitle(currentPageTitle.value, App.NAME),
|
|
49
|
-
}))
|
|
50
|
-
|
|
51
|
-
// Composables
|
|
52
|
-
const { isMobileSidebarOpen, toggleMobileSidebar } = useMobileSidebar()
|
|
53
|
-
|
|
54
|
-
</script>
|