ads-nuxt 0.1.1 → 0.1.2

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.
Files changed (74) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +567 -546
  3. package/app/app.config.ts +25 -25
  4. package/app/assets/ads/checkbox-check.svg +5 -5
  5. package/app/assets/ads/checkbox-minus.svg +5 -5
  6. package/app/assets/brand/farmarcas.svg +6 -6
  7. package/app/assets/brand/radar.svg +9 -9
  8. package/app/assets/css/component-tokens.css +403 -403
  9. package/app/assets/css/main.css +617 -617
  10. package/app/components/AdsBadge.vue +48 -48
  11. package/app/components/AdsBroadcast.vue +45 -45
  12. package/app/components/AdsButton.vue +569 -569
  13. package/app/components/AdsButtonGroup.vue +39 -39
  14. package/app/components/AdsButtonMenu.vue +48 -48
  15. package/app/components/AdsCard.vue +117 -117
  16. package/app/components/AdsCharttip.vue +78 -78
  17. package/app/components/AdsCheckbox.vue +77 -77
  18. package/app/components/AdsDatePicker.vue +473 -473
  19. package/app/components/AdsDropdownMenu.vue +19 -19
  20. package/app/components/AdsEmptyState.vue +58 -58
  21. package/app/components/AdsFarmarcasPill.vue +74 -74
  22. package/app/components/AdsFeatureCard.vue +217 -217
  23. package/app/components/AdsFileCard.vue +101 -101
  24. package/app/components/AdsFilterDropdown.vue +174 -174
  25. package/app/components/AdsFilterOption.vue +72 -72
  26. package/app/components/AdsFilterSelect.vue +202 -202
  27. package/app/components/AdsFooter.vue +25 -25
  28. package/app/components/AdsInput.vue +143 -143
  29. package/app/components/AdsListDropdown.vue +44 -44
  30. package/app/components/AdsLoading.vue +109 -109
  31. package/app/components/AdsMenuBar.vue +103 -103
  32. package/app/components/AdsMetricCard.vue +119 -119
  33. package/app/components/AdsMiniPill.vue +40 -40
  34. package/app/components/AdsModal.vue +157 -157
  35. package/app/components/AdsMonthPicker.vue +80 -80
  36. package/app/components/AdsNavbarApp.vue +67 -67
  37. package/app/components/AdsNavbarDesk.vue +62 -62
  38. package/app/components/AdsNotabilityPill.vue +27 -27
  39. package/app/components/AdsNumberInput.vue +166 -166
  40. package/app/components/AdsPagination.vue +91 -91
  41. package/app/components/AdsProductTag.vue +61 -61
  42. package/app/components/AdsRadio.vue +70 -70
  43. package/app/components/AdsSearchInput.vue +113 -113
  44. package/app/components/AdsSegmentedTabs.vue +28 -28
  45. package/app/components/AdsSideMenu.vue +101 -101
  46. package/app/components/AdsSmalltip.vue +44 -44
  47. package/app/components/AdsSteptip.vue +101 -101
  48. package/app/components/AdsSwitch.vue +59 -59
  49. package/app/components/AdsTable.vue +100 -100
  50. package/app/components/AdsTableToolbar.vue +44 -44
  51. package/app/components/AdsTabs.vue +51 -51
  52. package/app/components/AdsTextarea.vue +109 -109
  53. package/app/components/AdsToast.vue +181 -181
  54. package/app/components/AdsTooltip.vue +66 -66
  55. package/app/components/InvertedTooltip.vue +40 -40
  56. package/app/components/OverlayLoading.vue +173 -173
  57. package/app/components/ProgressBarLoading.vue +256 -256
  58. package/app/composables/useOverlayLoading.ts +66 -66
  59. package/app/locale/pt-br.ts +6 -6
  60. package/app/plugins/ads-toast.client.ts +24 -24
  61. package/app/theme/ads-theme.ts +370 -370
  62. package/app/theme/component-tokens.json +402 -402
  63. package/app/theme/component-tokens.ts +815 -815
  64. package/app/types/overlay-loading.types.ts +26 -26
  65. package/app/utils/ads-filter-select.ts +172 -172
  66. package/app/utils/ads-table.ts +204 -204
  67. package/app/utils/calendar-date.ts +128 -128
  68. package/app/utils/category-role.ts +45 -45
  69. package/app/utils/money.ts +77 -77
  70. package/app/utils/notability.ts +8 -8
  71. package/app/utils/parser.ts +134 -134
  72. package/app/utils/percentage.ts +54 -54
  73. package/nuxt.config.ts +31 -32
  74. package/package.json +48 -46
@@ -1,202 +1,202 @@
1
- <template>
2
- <div class="flex w-full min-w-0 flex-col gap-0.5">
3
- <p
4
- v-if="label"
5
- :id="labelId"
6
- class="text-[length:var(--ads-filter-label-size)] leading-[1.2] text-[var(--ads-text-secondary)]"
7
- >
8
- {{ label }}
9
- </p>
10
-
11
- <UPopover
12
- v-model:open="isOpen"
13
- :portal="true"
14
- :content="{ align: 'start', side: 'bottom', sideOffset: 4 }"
15
- :ui="popoverUi"
16
- >
17
- <button
18
- type="button"
19
- class="flex h-[var(--ads-filter-height)] max-w-full items-center gap-0.5 rounded-[var(--ads-filter-radius)] px-[var(--ads-filter-padding-x)] text-[length:var(--ads-filter-font-size)] leading-[1.3] transition-colors focus-visible:border-(length:--ads-border-width-slim) focus-visible:border-[var(--ads-filter-focus-border)] focus-visible:outline-none disabled:cursor-not-allowed"
20
- :class="[fieldClass, block ? 'w-full justify-between' : 'w-fit']"
21
- :disabled="disabled"
22
- :data-state="fieldState"
23
- :aria-haspopup="type === 'month' ? 'dialog' : 'listbox'"
24
- :aria-expanded="isOpen"
25
- :aria-invalid="error ? true : undefined"
26
- :aria-labelledby="label ? labelId : undefined"
27
- :aria-describedby="supportText ? supportId : undefined"
28
- >
29
- <InvertedTooltip
30
- :text="triggerLabel"
31
- :disabled="!triggerHasTooltip"
32
- :content="{ side: 'top', align: 'start', sideOffset: 4 }"
33
- >
34
- <span class="min-w-0 truncate text-left">{{ triggerLabel }}</span>
35
- </InvertedTooltip>
36
- <UIcon name="i-lucide-chevron-down" class="size-4 shrink-0 text-base" :class="chevronClass" />
37
- </button>
38
-
39
- <template #content>
40
- <AdsMonthPicker
41
- v-if="type === 'month'"
42
- v-model="monthModel"
43
- @pick="isOpen = false"
44
- />
45
- <AdsFilterDropdown
46
- v-else
47
- v-model="model"
48
- v-model:query="query"
49
- :type="listType"
50
- :options="options"
51
- :searchable="showSearch"
52
- :select-all="showSelectAll"
53
- :select-all-label="selectAllLabel"
54
- :empty-label="emptyLabel"
55
- :search-placeholder="searchPlaceholder"
56
- :list-label="label || 'Opções'"
57
- @pick="isOpen = false"
58
- />
59
- </template>
60
- </UPopover>
61
-
62
- <p
63
- v-if="supportText"
64
- :id="supportId"
65
- class="text-[length:var(--ads-filter-label-size)] leading-[1.2] text-[var(--ads-text-secondary)]"
66
- >
67
- {{ supportText }}
68
- </p>
69
- </div>
70
- </template>
71
-
72
- <script setup lang="ts">
73
- import { computed, ref, useId, watch } from "vue";
74
- import AdsFilterDropdown from "./AdsFilterDropdown.vue";
75
- import AdsMonthPicker from "./AdsMonthPicker.vue";
76
- import InvertedTooltip from "./InvertedTooltip.vue";
77
- import {
78
- filterLabelNeedsTooltip,
79
- filterTriggerLabel,
80
- type AdsFilterOption,
81
- type AdsFilterType,
82
- } from "../utils/ads-filter-select";
83
-
84
- const props = withDefaults(
85
- defineProps<{
86
- type: AdsFilterType;
87
- label?: string;
88
- hint?: string;
89
- error?: string;
90
- placeholder?: string;
91
- disabled?: boolean;
92
- options?: AdsFilterOption[];
93
- /** `null` = padrão do tipo (checkbox busca e seleciona todos). */
94
- searchable?: boolean | null;
95
- selectAll?: boolean | null;
96
- selectAllLabel?: string;
97
- allSelectedLabel?: string;
98
- emptyLabel?: string;
99
- searchPlaceholder?: string;
100
- /** O gatilho ocupa a largura do campo, como um select de formulário. */
101
- block?: boolean;
102
- }>(),
103
- {
104
- placeholder: "Selecione",
105
- disabled: false,
106
- options: () => [],
107
- searchable: null,
108
- selectAll: null,
109
- selectAllLabel: "Selecionar todos",
110
- allSelectedLabel: "Todos selecionados",
111
- emptyLabel: "Nenhum resultado",
112
- searchPlaceholder: "Pesquisar",
113
- block: false,
114
- },
115
- );
116
-
117
- const model = defineModel<string | string[]>({ required: true });
118
-
119
- const isOpen = ref(false);
120
- const query = ref("");
121
- const labelId = useId();
122
- const supportId = useId();
123
-
124
- const showSearch = computed(() =>
125
- props.searchable === null ? props.type === "checkbox" : props.searchable,
126
- );
127
- const showSelectAll = computed(() =>
128
- props.selectAll === null ? props.type === "checkbox" : props.selectAll,
129
- );
130
- const listType = computed(() => (props.type === "radio" ? "radio" : "checkbox"));
131
-
132
- const supportText = computed(() => props.error || props.hint || "");
133
-
134
- const hasValue = computed(() => {
135
- if (Array.isArray(model.value)) return model.value.length > 0;
136
- return model.value.length > 0;
137
- });
138
-
139
- const fieldState = computed(() => {
140
- if (props.disabled) return "disabled";
141
- if (props.error) return "error";
142
- if (isOpen.value) return "open";
143
- if (hasValue.value) return "selected";
144
- return "default";
145
- });
146
-
147
- const fieldClass = computed(() => {
148
- if (fieldState.value === "disabled") {
149
- return "border border-[var(--ads-filter-disabled-border)] bg-[var(--ads-filter-disabled-background)] text-[var(--ads-filter-disabled-text)]";
150
- }
151
- if (fieldState.value === "error") {
152
- return "border-(length:--ads-border-width-slim) border-[var(--ads-filter-error-border)] bg-[var(--ads-filter-background)] text-[var(--ads-filter-text)]";
153
- }
154
- if (fieldState.value === "open") {
155
- return "border-(length:--ads-border-width-slim) border-[var(--ads-filter-focus-border)] bg-[var(--ads-filter-background)] text-[var(--ads-filter-text)]";
156
- }
157
- if (fieldState.value === "selected") {
158
- return "border border-[var(--ads-filter-border)] hover:border-[var(--ads-filter-hover-border)] bg-ads-neutro-claro-20 text-[var(--ads-filter-text)]";
159
- }
160
- return "border border-[var(--ads-filter-border)] hover:border-[var(--ads-filter-hover-border)] bg-[var(--ads-filter-background)] text-[var(--ads-filter-text)]";
161
- });
162
-
163
- const chevronClass = computed(() => {
164
- if (fieldState.value === "disabled") return "text-ads-neutro-medio-60";
165
- if (fieldState.value === "selected") return "text-ads-neutro-escuro-500";
166
- return "text-ads-neutro-medio-100";
167
- });
168
-
169
- const triggerLabel = computed(() =>
170
- filterTriggerLabel({
171
- type: props.type,
172
- value: model.value,
173
- options: props.options,
174
- placeholder: props.placeholder,
175
- allSelectedLabel: props.allSelectedLabel,
176
- }),
177
- );
178
-
179
- const triggerHasTooltip = computed(() => filterLabelNeedsTooltip(triggerLabel.value));
180
-
181
- const monthModel = computed({
182
- get: () => (typeof model.value === "string" ? model.value : ""),
183
- set: (value: string) => {
184
- model.value = value;
185
- },
186
- });
187
-
188
- watch(isOpen, (open) => {
189
- if (!open) query.value = "";
190
- });
191
-
192
- watch(
193
- () => props.disabled,
194
- (disabled) => {
195
- if (disabled) isOpen.value = false;
196
- },
197
- );
198
-
199
- const popoverUi = {
200
- content: "z-50 w-auto overflow-visible bg-transparent p-0 shadow-none ring-0",
201
- };
202
- </script>
1
+ <template>
2
+ <div class="flex w-full min-w-0 flex-col gap-0.5">
3
+ <p
4
+ v-if="label"
5
+ :id="labelId"
6
+ class="text-[length:var(--ads-filter-label-size)] leading-[1.2] text-[var(--ads-text-secondary)]"
7
+ >
8
+ {{ label }}
9
+ </p>
10
+
11
+ <UPopover
12
+ v-model:open="isOpen"
13
+ :portal="true"
14
+ :content="{ align: 'start', side: 'bottom', sideOffset: 4 }"
15
+ :ui="popoverUi"
16
+ >
17
+ <button
18
+ type="button"
19
+ class="flex h-[var(--ads-filter-height)] max-w-full items-center gap-0.5 rounded-[var(--ads-filter-radius)] px-[var(--ads-filter-padding-x)] text-[length:var(--ads-filter-font-size)] leading-[1.3] transition-colors focus-visible:border-(length:--ads-border-width-slim) focus-visible:border-[var(--ads-filter-focus-border)] focus-visible:outline-none disabled:cursor-not-allowed"
20
+ :class="[fieldClass, block ? 'w-full justify-between' : 'w-fit']"
21
+ :disabled="disabled"
22
+ :data-state="fieldState"
23
+ :aria-haspopup="type === 'month' ? 'dialog' : 'listbox'"
24
+ :aria-expanded="isOpen"
25
+ :aria-invalid="error ? true : undefined"
26
+ :aria-labelledby="label ? labelId : undefined"
27
+ :aria-describedby="supportText ? supportId : undefined"
28
+ >
29
+ <InvertedTooltip
30
+ :text="triggerLabel"
31
+ :disabled="!triggerHasTooltip"
32
+ :content="{ side: 'top', align: 'start', sideOffset: 4 }"
33
+ >
34
+ <span class="min-w-0 truncate text-left">{{ triggerLabel }}</span>
35
+ </InvertedTooltip>
36
+ <UIcon name="i-lucide-chevron-down" class="size-4 shrink-0 text-base" :class="chevronClass" />
37
+ </button>
38
+
39
+ <template #content>
40
+ <AdsMonthPicker
41
+ v-if="type === 'month'"
42
+ v-model="monthModel"
43
+ @pick="isOpen = false"
44
+ />
45
+ <AdsFilterDropdown
46
+ v-else
47
+ v-model="model"
48
+ v-model:query="query"
49
+ :type="listType"
50
+ :options="options"
51
+ :searchable="showSearch"
52
+ :select-all="showSelectAll"
53
+ :select-all-label="selectAllLabel"
54
+ :empty-label="emptyLabel"
55
+ :search-placeholder="searchPlaceholder"
56
+ :list-label="label || 'Opções'"
57
+ @pick="isOpen = false"
58
+ />
59
+ </template>
60
+ </UPopover>
61
+
62
+ <p
63
+ v-if="supportText"
64
+ :id="supportId"
65
+ class="text-[length:var(--ads-filter-label-size)] leading-[1.2] text-[var(--ads-text-secondary)]"
66
+ >
67
+ {{ supportText }}
68
+ </p>
69
+ </div>
70
+ </template>
71
+
72
+ <script setup lang="ts">
73
+ import { computed, ref, useId, watch } from "vue";
74
+ import AdsFilterDropdown from "./AdsFilterDropdown.vue";
75
+ import AdsMonthPicker from "./AdsMonthPicker.vue";
76
+ import InvertedTooltip from "./InvertedTooltip.vue";
77
+ import {
78
+ filterLabelNeedsTooltip,
79
+ filterTriggerLabel,
80
+ type AdsFilterOption,
81
+ type AdsFilterType,
82
+ } from "../utils/ads-filter-select";
83
+
84
+ const props = withDefaults(
85
+ defineProps<{
86
+ type: AdsFilterType;
87
+ label?: string;
88
+ hint?: string;
89
+ error?: string;
90
+ placeholder?: string;
91
+ disabled?: boolean;
92
+ options?: AdsFilterOption[];
93
+ /** `null` = padrão do tipo (checkbox busca e seleciona todos). */
94
+ searchable?: boolean | null;
95
+ selectAll?: boolean | null;
96
+ selectAllLabel?: string;
97
+ allSelectedLabel?: string;
98
+ emptyLabel?: string;
99
+ searchPlaceholder?: string;
100
+ /** O gatilho ocupa a largura do campo, como um select de formulário. */
101
+ block?: boolean;
102
+ }>(),
103
+ {
104
+ placeholder: "Selecione",
105
+ disabled: false,
106
+ options: () => [],
107
+ searchable: null,
108
+ selectAll: null,
109
+ selectAllLabel: "Selecionar todos",
110
+ allSelectedLabel: "Todos selecionados",
111
+ emptyLabel: "Nenhum resultado",
112
+ searchPlaceholder: "Pesquisar",
113
+ block: false,
114
+ },
115
+ );
116
+
117
+ const model = defineModel<string | string[]>({ required: true });
118
+
119
+ const isOpen = ref(false);
120
+ const query = ref("");
121
+ const labelId = useId();
122
+ const supportId = useId();
123
+
124
+ const showSearch = computed(() =>
125
+ props.searchable === null ? props.type === "checkbox" : props.searchable,
126
+ );
127
+ const showSelectAll = computed(() =>
128
+ props.selectAll === null ? props.type === "checkbox" : props.selectAll,
129
+ );
130
+ const listType = computed(() => (props.type === "radio" ? "radio" : "checkbox"));
131
+
132
+ const supportText = computed(() => props.error || props.hint || "");
133
+
134
+ const hasValue = computed(() => {
135
+ if (Array.isArray(model.value)) return model.value.length > 0;
136
+ return model.value.length > 0;
137
+ });
138
+
139
+ const fieldState = computed(() => {
140
+ if (props.disabled) return "disabled";
141
+ if (props.error) return "error";
142
+ if (isOpen.value) return "open";
143
+ if (hasValue.value) return "selected";
144
+ return "default";
145
+ });
146
+
147
+ const fieldClass = computed(() => {
148
+ if (fieldState.value === "disabled") {
149
+ return "border border-[var(--ads-filter-disabled-border)] bg-[var(--ads-filter-disabled-background)] text-[var(--ads-filter-disabled-text)]";
150
+ }
151
+ if (fieldState.value === "error") {
152
+ return "border-(length:--ads-border-width-slim) border-[var(--ads-filter-error-border)] bg-[var(--ads-filter-background)] text-[var(--ads-filter-text)]";
153
+ }
154
+ if (fieldState.value === "open") {
155
+ return "border-(length:--ads-border-width-slim) border-[var(--ads-filter-focus-border)] bg-[var(--ads-filter-background)] text-[var(--ads-filter-text)]";
156
+ }
157
+ if (fieldState.value === "selected") {
158
+ return "border border-[var(--ads-filter-border)] hover:border-[var(--ads-filter-hover-border)] bg-ads-neutro-claro-20 text-[var(--ads-filter-text)]";
159
+ }
160
+ return "border border-[var(--ads-filter-border)] hover:border-[var(--ads-filter-hover-border)] bg-[var(--ads-filter-background)] text-[var(--ads-filter-text)]";
161
+ });
162
+
163
+ const chevronClass = computed(() => {
164
+ if (fieldState.value === "disabled") return "text-ads-neutro-medio-60";
165
+ if (fieldState.value === "selected") return "text-ads-neutro-escuro-500";
166
+ return "text-ads-neutro-medio-100";
167
+ });
168
+
169
+ const triggerLabel = computed(() =>
170
+ filterTriggerLabel({
171
+ type: props.type,
172
+ value: model.value,
173
+ options: props.options,
174
+ placeholder: props.placeholder,
175
+ allSelectedLabel: props.allSelectedLabel,
176
+ }),
177
+ );
178
+
179
+ const triggerHasTooltip = computed(() => filterLabelNeedsTooltip(triggerLabel.value));
180
+
181
+ const monthModel = computed({
182
+ get: () => (typeof model.value === "string" ? model.value : ""),
183
+ set: (value: string) => {
184
+ model.value = value;
185
+ },
186
+ });
187
+
188
+ watch(isOpen, (open) => {
189
+ if (!open) query.value = "";
190
+ });
191
+
192
+ watch(
193
+ () => props.disabled,
194
+ (disabled) => {
195
+ if (disabled) isOpen.value = false;
196
+ },
197
+ );
198
+
199
+ const popoverUi = {
200
+ content: "z-50 w-auto overflow-visible bg-transparent p-0 shadow-none ring-0",
201
+ };
202
+ </script>
@@ -1,25 +1,25 @@
1
- <template>
2
- <footer class="flex min-h-[var(--ads-footer-min-height)] w-full flex-wrap items-center justify-between gap-3 bg-[var(--ads-surface-card)] px-10 py-2">
3
- <p class="text-xs leading-4 text-[var(--ads-footer-text)]">
4
- <span class="font-bold">© Copyright Radar Farmarcas </span>
5
- <span>- Todos os direitos reservados.</span>
6
- </p>
7
- <p class="flex items-center gap-2 text-xs leading-4 text-[var(--ads-footer-text)]">
8
- <span>{{ developerLabel }}</span>
9
- <img :src="logoUrl" alt="Farmarcas" class="h-[var(--ads-footer-logo-height)] w-auto" />
10
- </p>
11
- </footer>
12
- </template>
13
-
14
- <script setup lang="ts">
15
- import logoUrl from "../assets/brand/farmarcas.svg?url";
16
-
17
- withDefaults(
18
- defineProps<{
19
- developerLabel?: string;
20
- }>(),
21
- {
22
- developerLabel: "Desenvolvido por",
23
- },
24
- );
25
- </script>
1
+ <template>
2
+ <footer class="flex min-h-[var(--ads-footer-min-height)] w-full flex-wrap items-center justify-between gap-3 bg-[var(--ads-surface-card)] px-10 py-2">
3
+ <p class="text-xs leading-4 text-[var(--ads-footer-text)]">
4
+ <span class="font-bold">© Copyright Radar Farmarcas </span>
5
+ <span>- Todos os direitos reservados.</span>
6
+ </p>
7
+ <p class="flex items-center gap-2 text-xs leading-4 text-[var(--ads-footer-text)]">
8
+ <span>{{ developerLabel }}</span>
9
+ <img :src="logoUrl" alt="Farmarcas" class="h-[var(--ads-footer-logo-height)] w-auto" />
10
+ </p>
11
+ </footer>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import logoUrl from "../assets/brand/farmarcas.svg?url";
16
+
17
+ withDefaults(
18
+ defineProps<{
19
+ developerLabel?: string;
20
+ }>(),
21
+ {
22
+ developerLabel: "Desenvolvido por",
23
+ },
24
+ );
25
+ </script>