ads-nuxt 0.1.1 → 0.1.3
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/LICENSE +21 -21
- package/README.md +577 -546
- package/app/app.config.ts +25 -25
- package/app/assets/ads/checkbox-check.svg +5 -5
- package/app/assets/ads/checkbox-minus.svg +5 -5
- package/app/assets/brand/farmarcas.svg +6 -6
- package/app/assets/brand/radar.svg +9 -9
- package/app/assets/css/component-tokens.css +403 -403
- package/app/assets/css/main.css +617 -617
- package/app/components/AdsBadge.vue +48 -48
- package/app/components/AdsBroadcast.vue +45 -45
- package/app/components/AdsButton.vue +569 -569
- package/app/components/AdsButtonGroup.vue +39 -39
- package/app/components/AdsButtonMenu.vue +48 -48
- package/app/components/AdsCard.vue +117 -117
- package/app/components/AdsCharttip.vue +78 -78
- package/app/components/AdsCheckbox.vue +77 -77
- package/app/components/AdsDatePicker.vue +473 -473
- package/app/components/AdsDropdownMenu.vue +19 -19
- package/app/components/AdsEmptyState.vue +58 -58
- package/app/components/AdsFarmarcasPill.vue +74 -74
- package/app/components/AdsFeatureCard.vue +217 -217
- package/app/components/AdsFileCard.vue +101 -101
- package/app/components/AdsFilterDropdown.vue +174 -174
- package/app/components/AdsFilterOption.vue +72 -72
- package/app/components/AdsFilterSelect.vue +202 -202
- package/app/components/AdsFooter.vue +25 -25
- package/app/components/AdsInput.vue +143 -143
- package/app/components/AdsListDropdown.vue +44 -44
- package/app/components/AdsLoading.vue +109 -109
- package/app/components/AdsMenuBar.vue +103 -103
- package/app/components/AdsMetricCard.vue +119 -119
- package/app/components/AdsMiniPill.vue +40 -40
- package/app/components/AdsModal.vue +157 -157
- package/app/components/AdsMonthPicker.vue +80 -80
- package/app/components/AdsNavbarApp.vue +67 -67
- package/app/components/AdsNavbarDesk.vue +62 -62
- package/app/components/AdsNotabilityPill.vue +27 -27
- package/app/components/AdsNumberInput.vue +166 -166
- package/app/components/AdsPagination.vue +91 -91
- package/app/components/AdsProductTag.vue +61 -61
- package/app/components/AdsRadio.vue +70 -70
- package/app/components/AdsSearchInput.vue +113 -113
- package/app/components/AdsSegmentedTabs.vue +28 -28
- package/app/components/AdsSideMenu.vue +101 -101
- package/app/components/AdsSmalltip.vue +44 -44
- package/app/components/AdsSteptip.vue +101 -101
- package/app/components/AdsSwitch.vue +59 -59
- package/app/components/AdsTable.vue +100 -100
- package/app/components/AdsTableToolbar.vue +44 -44
- package/app/components/AdsTabs.vue +51 -51
- package/app/components/AdsTextarea.vue +109 -109
- package/app/components/AdsToast.vue +181 -181
- package/app/components/AdsTooltip.vue +66 -66
- package/app/components/InvertedTooltip.vue +40 -40
- package/app/components/OverlayLoading.vue +173 -173
- package/app/components/ProgressBarLoading.vue +256 -256
- package/app/composables/useOverlayLoading.ts +66 -66
- package/app/locale/pt-br.ts +6 -6
- package/app/plugins/ads-toast.client.ts +24 -24
- package/app/theme/ads-theme.ts +370 -370
- package/app/theme/component-tokens.json +402 -402
- package/app/theme/component-tokens.ts +815 -815
- package/app/types/overlay-loading.types.ts +26 -26
- package/app/utils/ads-filter-select.ts +172 -172
- package/app/utils/ads-table.ts +204 -204
- package/app/utils/calendar-date.ts +128 -128
- package/app/utils/category-role.ts +45 -45
- package/app/utils/money.ts +77 -77
- package/app/utils/notability.ts +8 -8
- package/app/utils/parser.ts +134 -134
- package/app/utils/percentage.ts +54 -54
- package/nuxt.config.ts +31 -32
- package/package.json +55 -46
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="inline-flex" role="radiogroup" :aria-label="ariaLabel">
|
|
3
|
-
<button
|
|
4
|
-
v-for="(option, index) in options"
|
|
5
|
-
:key="option.value"
|
|
6
|
-
type="button"
|
|
7
|
-
role="radio"
|
|
8
|
-
class="-ml-px h-[var(--ads-button-group-height)] border border-[var(--ads-button-group-border)] px-4 text-[length:var(--ads-button-group-font-size)] text-[var(--ads-text-primary)] first:ml-0 focus-visible:z-10 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--ads-text-brand)]"
|
|
9
|
-
:class="[
|
|
10
|
-
index === 0 ? 'rounded-l-[var(--ads-radius-xsm)]' : '',
|
|
11
|
-
index === options.length - 1 ? 'rounded-r-[var(--ads-radius-xsm)]' : '',
|
|
12
|
-
model === option.value ? 'z-[1] bg-[var(--ads-button-group-selected)] font-bold' : 'bg-[var(--ads-surface-card)] font-normal',
|
|
13
|
-
]"
|
|
14
|
-
:aria-checked="model === option.value"
|
|
15
|
-
@click="model = option.value"
|
|
16
|
-
>
|
|
17
|
-
{{ option.label }}
|
|
18
|
-
</button>
|
|
19
|
-
</div>
|
|
20
|
-
</template>
|
|
21
|
-
|
|
22
|
-
<script setup lang="ts">
|
|
23
|
-
export type AdsButtonGroupOption = {
|
|
24
|
-
value: string;
|
|
25
|
-
label: string;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
withDefaults(
|
|
29
|
-
defineProps<{
|
|
30
|
-
options: AdsButtonGroupOption[];
|
|
31
|
-
ariaLabel?: string;
|
|
32
|
-
}>(),
|
|
33
|
-
{
|
|
34
|
-
ariaLabel: "Grupo de botões",
|
|
35
|
-
},
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
const model = defineModel<string>({ required: true });
|
|
39
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div class="inline-flex" role="radiogroup" :aria-label="ariaLabel">
|
|
3
|
+
<button
|
|
4
|
+
v-for="(option, index) in options"
|
|
5
|
+
:key="option.value"
|
|
6
|
+
type="button"
|
|
7
|
+
role="radio"
|
|
8
|
+
class="-ml-px h-[var(--ads-button-group-height)] border border-[var(--ads-button-group-border)] px-4 text-[length:var(--ads-button-group-font-size)] text-[var(--ads-text-primary)] first:ml-0 focus-visible:z-10 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--ads-text-brand)]"
|
|
9
|
+
:class="[
|
|
10
|
+
index === 0 ? 'rounded-l-[var(--ads-radius-xsm)]' : '',
|
|
11
|
+
index === options.length - 1 ? 'rounded-r-[var(--ads-radius-xsm)]' : '',
|
|
12
|
+
model === option.value ? 'z-[1] bg-[var(--ads-button-group-selected)] font-bold' : 'bg-[var(--ads-surface-card)] font-normal',
|
|
13
|
+
]"
|
|
14
|
+
:aria-checked="model === option.value"
|
|
15
|
+
@click="model = option.value"
|
|
16
|
+
>
|
|
17
|
+
{{ option.label }}
|
|
18
|
+
</button>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
export type AdsButtonGroupOption = {
|
|
24
|
+
value: string;
|
|
25
|
+
label: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
withDefaults(
|
|
29
|
+
defineProps<{
|
|
30
|
+
options: AdsButtonGroupOption[];
|
|
31
|
+
ariaLabel?: string;
|
|
32
|
+
}>(),
|
|
33
|
+
{
|
|
34
|
+
ariaLabel: "Grupo de botões",
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const model = defineModel<string>({ required: true });
|
|
39
|
+
</script>
|
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
class="flex w-[var(--ads-button-menu-width)] flex-col overflow-hidden rounded-[var(--ads-radius-xsm)] bg-[var(--ads-surface-card)] shadow-[var(--ads-shadow-level-1)]"
|
|
4
|
-
role="menu"
|
|
5
|
-
>
|
|
6
|
-
<button
|
|
7
|
-
v-for="option in options"
|
|
8
|
-
:key="option.value"
|
|
9
|
-
type="button"
|
|
10
|
-
role="menuitem"
|
|
11
|
-
class="flex flex-col border-b-[0.5px] border-[var(--ads-button-menu-border)] px-4 pt-2 pb-4 text-left last:border-b-0 hover:bg-ads-neutro-claro-20 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--ads-text-brand)]"
|
|
12
|
-
@click="emit('select', option.value)"
|
|
13
|
-
>
|
|
14
|
-
<span class="flex h-10 items-center gap-2 text-[length:var(--ads-button-menu-title-size)] leading-[1.3] font-medium text-[var(--ads-button-menu-title)]">
|
|
15
|
-
<UIcon v-if="showIcons" :name="option.icon || 'i-lucide-sparkles'" class="size-4 shrink-0" />
|
|
16
|
-
{{ option.title }}
|
|
17
|
-
</span>
|
|
18
|
-
<span v-if="showSubtitles && option.subtitle" class="line-clamp-2 text-[length:var(--ads-button-menu-subtitle-size)] leading-[1.2] text-[var(--ads-button-menu-subtitle)]">
|
|
19
|
-
{{ option.subtitle }}
|
|
20
|
-
</span>
|
|
21
|
-
</button>
|
|
22
|
-
</div>
|
|
23
|
-
</template>
|
|
24
|
-
|
|
25
|
-
<script setup lang="ts">
|
|
26
|
-
export type AdsButtonMenuOption = {
|
|
27
|
-
value: string;
|
|
28
|
-
title: string;
|
|
29
|
-
subtitle?: string;
|
|
30
|
-
icon?: string;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
withDefaults(
|
|
34
|
-
defineProps<{
|
|
35
|
-
options: AdsButtonMenuOption[];
|
|
36
|
-
showSubtitles?: boolean;
|
|
37
|
-
showIcons?: boolean;
|
|
38
|
-
}>(),
|
|
39
|
-
{
|
|
40
|
-
showSubtitles: true,
|
|
41
|
-
showIcons: true,
|
|
42
|
-
},
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
const emit = defineEmits<{
|
|
46
|
-
select: [value: string];
|
|
47
|
-
}>();
|
|
48
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="flex w-[var(--ads-button-menu-width)] flex-col overflow-hidden rounded-[var(--ads-radius-xsm)] bg-[var(--ads-surface-card)] shadow-[var(--ads-shadow-level-1)]"
|
|
4
|
+
role="menu"
|
|
5
|
+
>
|
|
6
|
+
<button
|
|
7
|
+
v-for="option in options"
|
|
8
|
+
:key="option.value"
|
|
9
|
+
type="button"
|
|
10
|
+
role="menuitem"
|
|
11
|
+
class="flex flex-col border-b-[0.5px] border-[var(--ads-button-menu-border)] px-4 pt-2 pb-4 text-left last:border-b-0 hover:bg-ads-neutro-claro-20 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--ads-text-brand)]"
|
|
12
|
+
@click="emit('select', option.value)"
|
|
13
|
+
>
|
|
14
|
+
<span class="flex h-10 items-center gap-2 text-[length:var(--ads-button-menu-title-size)] leading-[1.3] font-medium text-[var(--ads-button-menu-title)]">
|
|
15
|
+
<UIcon v-if="showIcons" :name="option.icon || 'i-lucide-sparkles'" class="size-4 shrink-0" />
|
|
16
|
+
{{ option.title }}
|
|
17
|
+
</span>
|
|
18
|
+
<span v-if="showSubtitles && option.subtitle" class="line-clamp-2 text-[length:var(--ads-button-menu-subtitle-size)] leading-[1.2] text-[var(--ads-button-menu-subtitle)]">
|
|
19
|
+
{{ option.subtitle }}
|
|
20
|
+
</span>
|
|
21
|
+
</button>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
export type AdsButtonMenuOption = {
|
|
27
|
+
value: string;
|
|
28
|
+
title: string;
|
|
29
|
+
subtitle?: string;
|
|
30
|
+
icon?: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
withDefaults(
|
|
34
|
+
defineProps<{
|
|
35
|
+
options: AdsButtonMenuOption[];
|
|
36
|
+
showSubtitles?: boolean;
|
|
37
|
+
showIcons?: boolean;
|
|
38
|
+
}>(),
|
|
39
|
+
{
|
|
40
|
+
showSubtitles: true,
|
|
41
|
+
showIcons: true,
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const emit = defineEmits<{
|
|
46
|
+
select: [value: string];
|
|
47
|
+
}>();
|
|
48
|
+
</script>
|
|
@@ -1,117 +1,117 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<component
|
|
3
|
-
:is="as"
|
|
4
|
-
:type="as === 'button' ? 'button' : undefined"
|
|
5
|
-
:disabled="as === 'button' ? disabled : undefined"
|
|
6
|
-
class="h-full border p-[var(--ads-card-padding)] text-left"
|
|
7
|
-
:class="[radiusClass, surfaceClass]"
|
|
8
|
-
>
|
|
9
|
-
<div
|
|
10
|
-
v-if="showHeader"
|
|
11
|
-
class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"
|
|
12
|
-
>
|
|
13
|
-
<div class="min-w-0 flex-1">
|
|
14
|
-
<slot name="header">
|
|
15
|
-
<p class="flex items-center justify-between gap-2 font-bold text-[var(--ads-card-title)]">
|
|
16
|
-
<span class="min-w-0">{{ title }}</span>
|
|
17
|
-
<slot name="hint" />
|
|
18
|
-
</p>
|
|
19
|
-
</slot>
|
|
20
|
-
</div>
|
|
21
|
-
<div v-if="$slots.actions" class="flex shrink-0 flex-wrap items-center gap-2">
|
|
22
|
-
<slot name="actions" />
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
|
|
26
|
-
<div
|
|
27
|
-
v-if="description || $slots.default"
|
|
28
|
-
:class="showHeader ? 'mt-2' : undefined"
|
|
29
|
-
>
|
|
30
|
-
<slot>
|
|
31
|
-
<p class="text-[length:var(--ads-card-body-size)] leading-relaxed text-[var(--ads-card-body)]">
|
|
32
|
-
{{ description }}
|
|
33
|
-
</p>
|
|
34
|
-
</slot>
|
|
35
|
-
</div>
|
|
36
|
-
|
|
37
|
-
<div
|
|
38
|
-
v-if="footerText || $slots.footer"
|
|
39
|
-
class="flex flex-wrap items-start justify-between gap-3"
|
|
40
|
-
:class="hasContentAboveFooter ? 'mt-4' : undefined"
|
|
41
|
-
>
|
|
42
|
-
<slot name="footer">
|
|
43
|
-
<p class="text-xs text-[var(--ads-text-secondary)]">
|
|
44
|
-
{{ footerText }}
|
|
45
|
-
</p>
|
|
46
|
-
</slot>
|
|
47
|
-
</div>
|
|
48
|
-
</component>
|
|
49
|
-
</template>
|
|
50
|
-
|
|
51
|
-
<script setup lang="ts">
|
|
52
|
-
import { computed, useSlots } from "vue";
|
|
53
|
-
|
|
54
|
-
const props = withDefaults(
|
|
55
|
-
defineProps<{
|
|
56
|
-
/** Título em negrito. O slot header substitui. */
|
|
57
|
-
title?: string;
|
|
58
|
-
/** Texto de apoio. O slot padrão substitui. */
|
|
59
|
-
description?: string;
|
|
60
|
-
/** Linha curta no rodapé. O slot footer substitui. */
|
|
61
|
-
footerText?: string;
|
|
62
|
-
/** `button` quando o cartão é a própria ação. */
|
|
63
|
-
as?: "div" | "button";
|
|
64
|
-
disabled?: boolean;
|
|
65
|
-
/** Realce de item escolhido, como um filtro ativo. */
|
|
66
|
-
selected?: boolean;
|
|
67
|
-
/** `sm` (8px) em cartões grandes; `md` (12px) é o padrão. */
|
|
68
|
-
radius?: "sm" | "md";
|
|
69
|
-
}>(),
|
|
70
|
-
{
|
|
71
|
-
as: "div",
|
|
72
|
-
disabled: false,
|
|
73
|
-
selected: false,
|
|
74
|
-
radius: "md",
|
|
75
|
-
},
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
const radiusClass = computed(() =>
|
|
79
|
-
props.radius === "sm"
|
|
80
|
-
? "rounded-[var(--ads-card-radius-sm)]"
|
|
81
|
-
: "rounded-[var(--ads-card-radius)]",
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
const surfaceClass = computed(() => {
|
|
85
|
-
const classes = [
|
|
86
|
-
props.selected
|
|
87
|
-
? "border-[var(--ads-card-selected-border)] bg-[var(--ads-card-selected-background)]"
|
|
88
|
-
: "border-[var(--ads-card-border)] bg-[var(--ads-card-background)]",
|
|
89
|
-
];
|
|
90
|
-
|
|
91
|
-
if (props.as === "button") {
|
|
92
|
-
classes.push(
|
|
93
|
-
"cursor-pointer transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--ads-text-primary)] disabled:cursor-not-allowed disabled:opacity-50",
|
|
94
|
-
);
|
|
95
|
-
if (!props.selected && !props.disabled) {
|
|
96
|
-
classes.push("hover:bg-[var(--color-neutral-100)]");
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return classes;
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const slots = useSlots();
|
|
104
|
-
|
|
105
|
-
const showHeader = computed(
|
|
106
|
-
() =>
|
|
107
|
-
Boolean(props.title) ||
|
|
108
|
-
Boolean(slots.header || slots.actions),
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
const hasContentAboveFooter = computed(
|
|
112
|
-
() =>
|
|
113
|
-
showHeader.value ||
|
|
114
|
-
Boolean(props.description) ||
|
|
115
|
-
Boolean(slots.default),
|
|
116
|
-
);
|
|
117
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:is="as"
|
|
4
|
+
:type="as === 'button' ? 'button' : undefined"
|
|
5
|
+
:disabled="as === 'button' ? disabled : undefined"
|
|
6
|
+
class="h-full border p-[var(--ads-card-padding)] text-left"
|
|
7
|
+
:class="[radiusClass, surfaceClass]"
|
|
8
|
+
>
|
|
9
|
+
<div
|
|
10
|
+
v-if="showHeader"
|
|
11
|
+
class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"
|
|
12
|
+
>
|
|
13
|
+
<div class="min-w-0 flex-1">
|
|
14
|
+
<slot name="header">
|
|
15
|
+
<p class="flex items-center justify-between gap-2 font-bold text-[var(--ads-card-title)]">
|
|
16
|
+
<span class="min-w-0">{{ title }}</span>
|
|
17
|
+
<slot name="hint" />
|
|
18
|
+
</p>
|
|
19
|
+
</slot>
|
|
20
|
+
</div>
|
|
21
|
+
<div v-if="$slots.actions" class="flex shrink-0 flex-wrap items-center gap-2">
|
|
22
|
+
<slot name="actions" />
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div
|
|
27
|
+
v-if="description || $slots.default"
|
|
28
|
+
:class="showHeader ? 'mt-2' : undefined"
|
|
29
|
+
>
|
|
30
|
+
<slot>
|
|
31
|
+
<p class="text-[length:var(--ads-card-body-size)] leading-relaxed text-[var(--ads-card-body)]">
|
|
32
|
+
{{ description }}
|
|
33
|
+
</p>
|
|
34
|
+
</slot>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div
|
|
38
|
+
v-if="footerText || $slots.footer"
|
|
39
|
+
class="flex flex-wrap items-start justify-between gap-3"
|
|
40
|
+
:class="hasContentAboveFooter ? 'mt-4' : undefined"
|
|
41
|
+
>
|
|
42
|
+
<slot name="footer">
|
|
43
|
+
<p class="text-xs text-[var(--ads-text-secondary)]">
|
|
44
|
+
{{ footerText }}
|
|
45
|
+
</p>
|
|
46
|
+
</slot>
|
|
47
|
+
</div>
|
|
48
|
+
</component>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<script setup lang="ts">
|
|
52
|
+
import { computed, useSlots } from "vue";
|
|
53
|
+
|
|
54
|
+
const props = withDefaults(
|
|
55
|
+
defineProps<{
|
|
56
|
+
/** Título em negrito. O slot header substitui. */
|
|
57
|
+
title?: string;
|
|
58
|
+
/** Texto de apoio. O slot padrão substitui. */
|
|
59
|
+
description?: string;
|
|
60
|
+
/** Linha curta no rodapé. O slot footer substitui. */
|
|
61
|
+
footerText?: string;
|
|
62
|
+
/** `button` quando o cartão é a própria ação. */
|
|
63
|
+
as?: "div" | "button";
|
|
64
|
+
disabled?: boolean;
|
|
65
|
+
/** Realce de item escolhido, como um filtro ativo. */
|
|
66
|
+
selected?: boolean;
|
|
67
|
+
/** `sm` (8px) em cartões grandes; `md` (12px) é o padrão. */
|
|
68
|
+
radius?: "sm" | "md";
|
|
69
|
+
}>(),
|
|
70
|
+
{
|
|
71
|
+
as: "div",
|
|
72
|
+
disabled: false,
|
|
73
|
+
selected: false,
|
|
74
|
+
radius: "md",
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const radiusClass = computed(() =>
|
|
79
|
+
props.radius === "sm"
|
|
80
|
+
? "rounded-[var(--ads-card-radius-sm)]"
|
|
81
|
+
: "rounded-[var(--ads-card-radius)]",
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const surfaceClass = computed(() => {
|
|
85
|
+
const classes = [
|
|
86
|
+
props.selected
|
|
87
|
+
? "border-[var(--ads-card-selected-border)] bg-[var(--ads-card-selected-background)]"
|
|
88
|
+
: "border-[var(--ads-card-border)] bg-[var(--ads-card-background)]",
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
if (props.as === "button") {
|
|
92
|
+
classes.push(
|
|
93
|
+
"cursor-pointer transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--ads-text-primary)] disabled:cursor-not-allowed disabled:opacity-50",
|
|
94
|
+
);
|
|
95
|
+
if (!props.selected && !props.disabled) {
|
|
96
|
+
classes.push("hover:bg-[var(--color-neutral-100)]");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return classes;
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const slots = useSlots();
|
|
104
|
+
|
|
105
|
+
const showHeader = computed(
|
|
106
|
+
() =>
|
|
107
|
+
Boolean(props.title) ||
|
|
108
|
+
Boolean(slots.header || slots.actions),
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const hasContentAboveFooter = computed(
|
|
112
|
+
() =>
|
|
113
|
+
showHeader.value ||
|
|
114
|
+
Boolean(props.description) ||
|
|
115
|
+
Boolean(slots.default),
|
|
116
|
+
);
|
|
117
|
+
</script>
|
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<DefinePanel>
|
|
3
|
-
<div class="flex min-w-[var(--ads-charttip-min-width)] flex-col gap-4 rounded-[var(--ads-tooltip-radius)] bg-[var(--ads-tooltip-bg)] p-4 text-[var(--ads-tooltip-title)] shadow-[var(--ads-shadow-level-1)]">
|
|
4
|
-
<p v-if="title" class="text-center text-base leading-[1.3] font-bold">{{ title }}</p>
|
|
5
|
-
<ul class="flex flex-col gap-2">
|
|
6
|
-
<li v-for="(row, index) in rows" :key="index" class="flex items-center gap-2 text-sm leading-[1.3]">
|
|
7
|
-
<span class="size-[var(--ads-charttip-swatch)] shrink-0 rounded-[var(--ads-radius-xsm)]" :class="row.colorClass" :style="row.color ? { background: row.color } : undefined" />
|
|
8
|
-
<span class="min-w-0 flex-1">{{ row.label }}</span>
|
|
9
|
-
<span>{{ row.value }}</span>
|
|
10
|
-
</li>
|
|
11
|
-
</ul>
|
|
12
|
-
</div>
|
|
13
|
-
</DefinePanel>
|
|
14
|
-
|
|
15
|
-
<UTooltip
|
|
16
|
-
v-if="hasTrigger"
|
|
17
|
-
:delay-duration="delayDuration"
|
|
18
|
-
:content="{ side, align: 'center', sideOffset: 8 }"
|
|
19
|
-
:ui="tooltipUi"
|
|
20
|
-
>
|
|
21
|
-
<slot />
|
|
22
|
-
<template #content>
|
|
23
|
-
<ReusePanel />
|
|
24
|
-
</template>
|
|
25
|
-
</UTooltip>
|
|
26
|
-
<ReusePanel v-else />
|
|
27
|
-
</template>
|
|
28
|
-
|
|
29
|
-
<script setup lang="ts">
|
|
30
|
-
import { computed, useSlots } from "vue";
|
|
31
|
-
import { createReusableTemplate } from "@vueuse/core";
|
|
32
|
-
|
|
33
|
-
export type AdsCharttipRow = {
|
|
34
|
-
label: string;
|
|
35
|
-
value: string;
|
|
36
|
-
/** Classe de fundo, como `bg-ads-grafico-c1-400`. */
|
|
37
|
-
colorClass?: string;
|
|
38
|
-
/** Cor sem token. Preferir `colorClass`. */
|
|
39
|
-
color?: string;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const props = withDefaults(
|
|
43
|
-
defineProps<{
|
|
44
|
-
title?: string;
|
|
45
|
-
rows?: AdsCharttipRow[];
|
|
46
|
-
/** Figma `Property 1`. Com slot, escolhe o lado em que o painel abre, como no AdsTooltip. A seta não é desenhada. */
|
|
47
|
-
wing?: "up" | "down" | "left" | "right";
|
|
48
|
-
delayDuration?: number;
|
|
49
|
-
}>(),
|
|
50
|
-
{
|
|
51
|
-
title: "Título",
|
|
52
|
-
rows: () => [
|
|
53
|
-
{ label: "Série 1", value: "12", colorClass: "bg-ads-grafico-c1-400" },
|
|
54
|
-
{ label: "Série 2", value: "8", colorClass: "bg-ads-innovation-500" },
|
|
55
|
-
{ label: "Série 3", value: "5", colorClass: "bg-ads-grafico-c3-400" },
|
|
56
|
-
],
|
|
57
|
-
wing: "down",
|
|
58
|
-
delayDuration: 150,
|
|
59
|
-
},
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
const [DefinePanel, ReusePanel] = createReusableTemplate();
|
|
63
|
-
|
|
64
|
-
const slots = useSlots();
|
|
65
|
-
const hasTrigger = computed(() => Boolean(slots.default));
|
|
66
|
-
|
|
67
|
-
const side = computed(() => {
|
|
68
|
-
if (props.wing === "down") return "bottom" as const;
|
|
69
|
-
if (props.wing === "left") return "left" as const;
|
|
70
|
-
if (props.wing === "right") return "right" as const;
|
|
71
|
-
return "top" as const;
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
/** O painel já tem fundo, raio e sombra: o conteúdo do UTooltip só posiciona. */
|
|
75
|
-
const tooltipUi = {
|
|
76
|
-
content: "z-[70] h-auto rounded-none bg-transparent p-0 shadow-none ring-0",
|
|
77
|
-
};
|
|
78
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<DefinePanel>
|
|
3
|
+
<div class="flex min-w-[var(--ads-charttip-min-width)] flex-col gap-4 rounded-[var(--ads-tooltip-radius)] bg-[var(--ads-tooltip-bg)] p-4 text-[var(--ads-tooltip-title)] shadow-[var(--ads-shadow-level-1)]">
|
|
4
|
+
<p v-if="title" class="text-center text-base leading-[1.3] font-bold">{{ title }}</p>
|
|
5
|
+
<ul class="flex flex-col gap-2">
|
|
6
|
+
<li v-for="(row, index) in rows" :key="index" class="flex items-center gap-2 text-sm leading-[1.3]">
|
|
7
|
+
<span class="size-[var(--ads-charttip-swatch)] shrink-0 rounded-[var(--ads-radius-xsm)]" :class="row.colorClass" :style="row.color ? { background: row.color } : undefined" />
|
|
8
|
+
<span class="min-w-0 flex-1">{{ row.label }}</span>
|
|
9
|
+
<span>{{ row.value }}</span>
|
|
10
|
+
</li>
|
|
11
|
+
</ul>
|
|
12
|
+
</div>
|
|
13
|
+
</DefinePanel>
|
|
14
|
+
|
|
15
|
+
<UTooltip
|
|
16
|
+
v-if="hasTrigger"
|
|
17
|
+
:delay-duration="delayDuration"
|
|
18
|
+
:content="{ side, align: 'center', sideOffset: 8 }"
|
|
19
|
+
:ui="tooltipUi"
|
|
20
|
+
>
|
|
21
|
+
<slot />
|
|
22
|
+
<template #content>
|
|
23
|
+
<ReusePanel />
|
|
24
|
+
</template>
|
|
25
|
+
</UTooltip>
|
|
26
|
+
<ReusePanel v-else />
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
import { computed, useSlots } from "vue";
|
|
31
|
+
import { createReusableTemplate } from "@vueuse/core";
|
|
32
|
+
|
|
33
|
+
export type AdsCharttipRow = {
|
|
34
|
+
label: string;
|
|
35
|
+
value: string;
|
|
36
|
+
/** Classe de fundo, como `bg-ads-grafico-c1-400`. */
|
|
37
|
+
colorClass?: string;
|
|
38
|
+
/** Cor sem token. Preferir `colorClass`. */
|
|
39
|
+
color?: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const props = withDefaults(
|
|
43
|
+
defineProps<{
|
|
44
|
+
title?: string;
|
|
45
|
+
rows?: AdsCharttipRow[];
|
|
46
|
+
/** Figma `Property 1`. Com slot, escolhe o lado em que o painel abre, como no AdsTooltip. A seta não é desenhada. */
|
|
47
|
+
wing?: "up" | "down" | "left" | "right";
|
|
48
|
+
delayDuration?: number;
|
|
49
|
+
}>(),
|
|
50
|
+
{
|
|
51
|
+
title: "Título",
|
|
52
|
+
rows: () => [
|
|
53
|
+
{ label: "Série 1", value: "12", colorClass: "bg-ads-grafico-c1-400" },
|
|
54
|
+
{ label: "Série 2", value: "8", colorClass: "bg-ads-innovation-500" },
|
|
55
|
+
{ label: "Série 3", value: "5", colorClass: "bg-ads-grafico-c3-400" },
|
|
56
|
+
],
|
|
57
|
+
wing: "down",
|
|
58
|
+
delayDuration: 150,
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const [DefinePanel, ReusePanel] = createReusableTemplate();
|
|
63
|
+
|
|
64
|
+
const slots = useSlots();
|
|
65
|
+
const hasTrigger = computed(() => Boolean(slots.default));
|
|
66
|
+
|
|
67
|
+
const side = computed(() => {
|
|
68
|
+
if (props.wing === "down") return "bottom" as const;
|
|
69
|
+
if (props.wing === "left") return "left" as const;
|
|
70
|
+
if (props.wing === "right") return "right" as const;
|
|
71
|
+
return "top" as const;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/** O painel já tem fundo, raio e sombra: o conteúdo do UTooltip só posiciona. */
|
|
75
|
+
const tooltipUi = {
|
|
76
|
+
content: "z-[70] h-auto rounded-none bg-transparent p-0 shadow-none ring-0",
|
|
77
|
+
};
|
|
78
|
+
</script>
|