@frigear-nu/ui 0.0.0-stage → 0.0.4
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/README.md +5 -2
- package/dist/module.d.mts +5 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +52 -0
- package/dist/runtime/components/Admin/AdminPageHeader.d.vue.ts +21 -0
- package/dist/runtime/components/Admin/AdminPageHeader.vue +45 -0
- package/dist/runtime/components/Admin/AdminPageHeader.vue.d.ts +21 -0
- package/dist/runtime/components/App/AppPageHeader.d.vue.ts +23 -0
- package/dist/runtime/components/App/AppPageHeader.vue +58 -0
- package/dist/runtime/components/App/AppPageHeader.vue.d.ts +23 -0
- package/dist/runtime/components/ConfirmDialog.d.vue.ts +15 -0
- package/dist/runtime/components/ConfirmDialog.vue +32 -0
- package/dist/runtime/components/ConfirmDialog.vue.d.ts +15 -0
- package/dist/runtime/components/global/CurrencyInput.d.vue.ts +10 -0
- package/dist/runtime/components/global/CurrencyInput.vue +39 -0
- package/dist/runtime/components/global/CurrencyInput.vue.d.ts +10 -0
- package/dist/runtime/components/global/DateInput.d.vue.ts +17 -0
- package/dist/runtime/components/global/DateInput.vue +62 -0
- package/dist/runtime/components/global/DateInput.vue.d.ts +17 -0
- package/dist/runtime/components/global/IconInput.d.vue.ts +19 -0
- package/dist/runtime/components/global/IconInput.vue +194 -0
- package/dist/runtime/components/global/IconInput.vue.d.ts +19 -0
- package/dist/runtime/components/global/IntervalInput.d.vue.ts +10 -0
- package/dist/runtime/components/global/IntervalInput.vue +51 -0
- package/dist/runtime/components/global/IntervalInput.vue.d.ts +10 -0
- package/dist/runtime/components/global/MonacoCodeEditor.d.vue.ts +20 -0
- package/dist/runtime/components/global/MonacoCodeEditor.vue +79 -0
- package/dist/runtime/components/global/MonacoCodeEditor.vue.d.ts +20 -0
- package/dist/runtime/components/global/MoneyInput.d.vue.ts +25 -0
- package/dist/runtime/components/global/MoneyInput.vue +65 -0
- package/dist/runtime/components/global/MoneyInput.vue.d.ts +25 -0
- package/dist/runtime/components/global/SwitchToggle.d.vue.ts +10 -0
- package/dist/runtime/components/global/SwitchToggle.vue +9 -0
- package/dist/runtime/components/global/SwitchToggle.vue.d.ts +10 -0
- package/dist/runtime/components/global/TagInput.d.vue.ts +20 -0
- package/dist/runtime/components/global/TagInput.vue +15 -0
- package/dist/runtime/components/global/TagInput.vue.d.ts +20 -0
- package/dist/runtime/components/global/UrlInput.d.vue.ts +12 -0
- package/dist/runtime/components/global/UrlInput.vue +28 -0
- package/dist/runtime/components/global/UrlInput.vue.d.ts +12 -0
- package/dist/runtime/composables/index.d.ts +1 -0
- package/dist/runtime/composables/index.js +1 -0
- package/dist/runtime/composables/useConfirmDialog.d.ts +6 -0
- package/dist/runtime/composables/useConfirmDialog.js +11 -0
- package/dist/runtime/i18n/lang/da.json +25 -0
- package/dist/runtime/i18n/lang/en.json +25 -0
- package/dist/runtime/utils/table.d.ts +11 -0
- package/dist/runtime/utils/table.js +23 -0
- package/dist/types.d.mts +7 -0
- package/package.json +72 -3
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, computed, watch } from "vue";
|
|
3
|
+
import { useDebounceFn } from "@vueuse/core";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
formItem: { type: Object, required: false, default: () => ({}) }
|
|
6
|
+
});
|
|
7
|
+
const model = defineModel({ type: String, ...{ default: "" } });
|
|
8
|
+
const HYPHENATED_COLLECTION_PREFIXES = [
|
|
9
|
+
"material-symbols-light",
|
|
10
|
+
"material-symbols",
|
|
11
|
+
"fluent-emoji-high-contrast",
|
|
12
|
+
"fluent-emoji-flat",
|
|
13
|
+
"fluent-emoji",
|
|
14
|
+
"simple-icons",
|
|
15
|
+
"flat-color-icons",
|
|
16
|
+
"line-md",
|
|
17
|
+
"svg-spinners",
|
|
18
|
+
"vscode-icons",
|
|
19
|
+
"game-icons",
|
|
20
|
+
"file-icons",
|
|
21
|
+
"flag-icons",
|
|
22
|
+
"circle-flags",
|
|
23
|
+
"fa6-brands",
|
|
24
|
+
"fa6-regular",
|
|
25
|
+
"fa6-solid",
|
|
26
|
+
"fa-brands",
|
|
27
|
+
"fa-regular",
|
|
28
|
+
"fa-solid",
|
|
29
|
+
"skill-icons",
|
|
30
|
+
"token-branded"
|
|
31
|
+
];
|
|
32
|
+
function normalizeIconName(stored) {
|
|
33
|
+
if (!stored.startsWith("i-")) {
|
|
34
|
+
return stored;
|
|
35
|
+
}
|
|
36
|
+
const body = stored.slice(2);
|
|
37
|
+
if (body.includes(":")) {
|
|
38
|
+
return stored;
|
|
39
|
+
}
|
|
40
|
+
for (const prefix of HYPHENATED_COLLECTION_PREFIXES) {
|
|
41
|
+
const lead = `${prefix}-`;
|
|
42
|
+
if (body.startsWith(lead) && body.length > lead.length) {
|
|
43
|
+
return `i-${prefix}:${body.slice(lead.length)}`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return stored;
|
|
47
|
+
}
|
|
48
|
+
const resolvedIconName = computed(() => normalizeIconName(model.value));
|
|
49
|
+
const search = ref("");
|
|
50
|
+
const icons = ref([]);
|
|
51
|
+
const isLoading = ref(false);
|
|
52
|
+
const popoverOpen = ref(false);
|
|
53
|
+
function resolveIconLibraries(fieldOptions, globalLibraries) {
|
|
54
|
+
if (Array.isArray(fieldOptions) && fieldOptions.length > 0) {
|
|
55
|
+
return fieldOptions;
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(globalLibraries) && globalLibraries.length > 0) {
|
|
58
|
+
return globalLibraries;
|
|
59
|
+
}
|
|
60
|
+
return "all";
|
|
61
|
+
}
|
|
62
|
+
const iconLibraries = computed(() => {
|
|
63
|
+
return resolveIconLibraries(
|
|
64
|
+
props.formItem?.options,
|
|
65
|
+
[]
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
async function fetchIcons(query) {
|
|
69
|
+
if (!query || query.length < 2) {
|
|
70
|
+
icons.value = [];
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
isLoading.value = true;
|
|
74
|
+
try {
|
|
75
|
+
const prefixes = iconLibraries.value === "all" ? "" : iconLibraries.value.join(",");
|
|
76
|
+
const data = await $fetch(
|
|
77
|
+
`https://api.iconify.design/search?query=${encodeURIComponent(query)}&limit=30` + (prefixes ? `&prefixes=${prefixes}` : "")
|
|
78
|
+
);
|
|
79
|
+
icons.value = data.icons || [];
|
|
80
|
+
} catch {
|
|
81
|
+
icons.value = [];
|
|
82
|
+
} finally {
|
|
83
|
+
isLoading.value = false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const debouncedFetch = useDebounceFn(fetchIcons, 300);
|
|
87
|
+
watch(search, (value) => {
|
|
88
|
+
debouncedFetch(value);
|
|
89
|
+
});
|
|
90
|
+
function selectIcon(icon) {
|
|
91
|
+
model.value = `i-${icon}`;
|
|
92
|
+
popoverOpen.value = false;
|
|
93
|
+
search.value = "";
|
|
94
|
+
icons.value = [];
|
|
95
|
+
}
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
<template>
|
|
99
|
+
<div class="flex items-center gap-1">
|
|
100
|
+
<div class="flex items-center justify-center size-8 bg-muted border border-muted rounded-md shrink-0">
|
|
101
|
+
<UIcon
|
|
102
|
+
v-if="model"
|
|
103
|
+
:name="resolvedIconName"
|
|
104
|
+
class="size-5"
|
|
105
|
+
/>
|
|
106
|
+
<UIcon
|
|
107
|
+
v-else
|
|
108
|
+
name="i-lucide-shapes"
|
|
109
|
+
class="size-5 text-dimmed"
|
|
110
|
+
/>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<UInput
|
|
114
|
+
v-model="model"
|
|
115
|
+
placeholder="Select icon..."
|
|
116
|
+
class="flex-1"
|
|
117
|
+
>
|
|
118
|
+
<template #trailing>
|
|
119
|
+
<UPopover
|
|
120
|
+
v-model:open="popoverOpen"
|
|
121
|
+
:content="{ side: 'left' }"
|
|
122
|
+
:ui="{ content: 'z-auto' }"
|
|
123
|
+
>
|
|
124
|
+
<UButton
|
|
125
|
+
color="neutral"
|
|
126
|
+
variant="ghost"
|
|
127
|
+
icon="i-lucide-search"
|
|
128
|
+
class="cursor-pointer"
|
|
129
|
+
/>
|
|
130
|
+
|
|
131
|
+
<template #content>
|
|
132
|
+
<div class="p-3 w-80">
|
|
133
|
+
<UInput
|
|
134
|
+
v-model="search"
|
|
135
|
+
placeholder="Find icons..."
|
|
136
|
+
icon="i-lucide-search"
|
|
137
|
+
autofocus
|
|
138
|
+
class="mb-3 w-full"
|
|
139
|
+
/>
|
|
140
|
+
|
|
141
|
+
<div
|
|
142
|
+
v-if="isLoading"
|
|
143
|
+
class="flex items-center justify-center py-4"
|
|
144
|
+
>
|
|
145
|
+
<UIcon
|
|
146
|
+
name="i-lucide-loader-2"
|
|
147
|
+
class="size-5 animate-spin text-muted"
|
|
148
|
+
/>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<div
|
|
152
|
+
v-else-if="icons.length > 0"
|
|
153
|
+
style="display: grid; grid-template-columns: repeat(6, 1fr);"
|
|
154
|
+
class="gap-1.5 max-h-48 overflow-y-auto"
|
|
155
|
+
>
|
|
156
|
+
<div
|
|
157
|
+
v-for="icon in icons"
|
|
158
|
+
:key="icon"
|
|
159
|
+
class="flex items-center justify-center"
|
|
160
|
+
>
|
|
161
|
+
<UTooltip :text="icon">
|
|
162
|
+
<UButton
|
|
163
|
+
color="neutral"
|
|
164
|
+
variant="soft"
|
|
165
|
+
:icon="`i-${icon}`"
|
|
166
|
+
@click="selectIcon(icon)"
|
|
167
|
+
/>
|
|
168
|
+
</UTooltip>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
<p
|
|
172
|
+
v-else-if="search.length >= 2"
|
|
173
|
+
class="text-xs text-muted text-center py-4"
|
|
174
|
+
>
|
|
175
|
+
No icons found...
|
|
176
|
+
</p>
|
|
177
|
+
|
|
178
|
+
<p
|
|
179
|
+
v-else
|
|
180
|
+
class="text-sm text-muted text-center py-4"
|
|
181
|
+
>
|
|
182
|
+
e.g Lamp, Book or Dashboard
|
|
183
|
+
</p>
|
|
184
|
+
|
|
185
|
+
<p class="text-xs text-dimmed mt-2">
|
|
186
|
+
Libraries: {{ iconLibraries === "all" ? "All" : iconLibraries.join(", ") }}
|
|
187
|
+
</p>
|
|
188
|
+
</div>
|
|
189
|
+
</template>
|
|
190
|
+
</UPopover>
|
|
191
|
+
</template>
|
|
192
|
+
</UInput>
|
|
193
|
+
</div>
|
|
194
|
+
</template>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
type FormItem = {
|
|
2
|
+
options?: string[];
|
|
3
|
+
};
|
|
4
|
+
type __VLS_Props = {
|
|
5
|
+
formItem?: FormItem;
|
|
6
|
+
};
|
|
7
|
+
type __VLS_ModelProps = {
|
|
8
|
+
modelValue?: string;
|
|
9
|
+
};
|
|
10
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
11
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
12
|
+
"update:modelValue": (value: string) => any;
|
|
13
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
14
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
15
|
+
}>, {
|
|
16
|
+
formItem: FormItem;
|
|
17
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
declare const _default: typeof __VLS_export;
|
|
19
|
+
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type __VLS_ModelProps = {
|
|
2
|
+
modelValue?: number;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: number) => any;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
7
|
+
"onUpdate:modelValue"?: ((value: number) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const UNIT_SECONDS = {
|
|
3
|
+
minutes: 60,
|
|
4
|
+
hours: 3600,
|
|
5
|
+
days: 86400
|
|
6
|
+
};
|
|
7
|
+
const units = [
|
|
8
|
+
{ label: "Minutes", value: "minutes" },
|
|
9
|
+
{ label: "Hours", value: "hours" },
|
|
10
|
+
{ label: "Days", value: "days" }
|
|
11
|
+
];
|
|
12
|
+
const seconds = defineModel({ type: Number, ...{ default: 86400 } });
|
|
13
|
+
const unit = ref("days");
|
|
14
|
+
const amount = ref(1);
|
|
15
|
+
function secondsToUnit(secs, u) {
|
|
16
|
+
return Math.round(secs / UNIT_SECONDS[u]);
|
|
17
|
+
}
|
|
18
|
+
function bestUnit(secs) {
|
|
19
|
+
if (secs % UNIT_SECONDS.days === 0) return "days";
|
|
20
|
+
if (secs % UNIT_SECONDS.hours === 0) return "hours";
|
|
21
|
+
return "minutes";
|
|
22
|
+
}
|
|
23
|
+
watch(seconds, (secs) => {
|
|
24
|
+
const u = bestUnit(secs);
|
|
25
|
+
unit.value = u;
|
|
26
|
+
amount.value = secondsToUnit(secs, u);
|
|
27
|
+
}, { immediate: true });
|
|
28
|
+
function onUpdate() {
|
|
29
|
+
const minSeconds = 60;
|
|
30
|
+
const raw = (amount.value || 1) * UNIT_SECONDS[unit.value];
|
|
31
|
+
seconds.value = Math.max(minSeconds, raw);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<div class="flex gap-2 w-full">
|
|
37
|
+
<UInputNumber
|
|
38
|
+
v-model="amount"
|
|
39
|
+
class="flex-1"
|
|
40
|
+
:min="1"
|
|
41
|
+
@update:model-value="onUpdate"
|
|
42
|
+
/>
|
|
43
|
+
<USelectMenu
|
|
44
|
+
v-model="unit"
|
|
45
|
+
:items="units"
|
|
46
|
+
value-key="value"
|
|
47
|
+
class="w-32"
|
|
48
|
+
@update:model-value="onUpdate"
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type __VLS_ModelProps = {
|
|
2
|
+
modelValue?: number;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: number) => any;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
7
|
+
"onUpdate:modelValue"?: ((value: number) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
language?: string;
|
|
3
|
+
height?: string;
|
|
4
|
+
fullscreen?: boolean;
|
|
5
|
+
};
|
|
6
|
+
type __VLS_ModelProps = {
|
|
7
|
+
modelValue?: string;
|
|
8
|
+
};
|
|
9
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
10
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
14
|
+
}>, {
|
|
15
|
+
language: string;
|
|
16
|
+
height: string;
|
|
17
|
+
fullscreen: boolean;
|
|
18
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
|
+
declare const _default: typeof __VLS_export;
|
|
20
|
+
export default _default;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, computed } from "vue";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
language: { type: String, required: false, default: "typescript" },
|
|
5
|
+
height: { type: String, required: false, default: "160px" },
|
|
6
|
+
fullscreen: { type: Boolean, required: false, default: true }
|
|
7
|
+
});
|
|
8
|
+
const modelValue = defineModel({ type: String });
|
|
9
|
+
const isModalOpen = ref(false);
|
|
10
|
+
const editorOptions = {
|
|
11
|
+
minimap: { enabled: false },
|
|
12
|
+
scrollBeyondLastLine: false,
|
|
13
|
+
fontSize: 13,
|
|
14
|
+
tabSize: 2,
|
|
15
|
+
theme: "vs-dark"
|
|
16
|
+
};
|
|
17
|
+
const slotName = computed(() => {
|
|
18
|
+
return props.fullscreen ? "body" : "content";
|
|
19
|
+
});
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<div class="flex flex-col gap-1">
|
|
24
|
+
<div class="relative">
|
|
25
|
+
<MonacoEditor
|
|
26
|
+
v-model="modelValue"
|
|
27
|
+
:lang="language"
|
|
28
|
+
:options="editorOptions"
|
|
29
|
+
class="rounded-md overflow-hidden border border-default"
|
|
30
|
+
:style="{ height }"
|
|
31
|
+
>
|
|
32
|
+
<div
|
|
33
|
+
class="rounded-md border border-default bg-muted animate-pulse"
|
|
34
|
+
:style="{ height }"
|
|
35
|
+
/>
|
|
36
|
+
</MonacoEditor>
|
|
37
|
+
<UButton
|
|
38
|
+
v-if="!isModalOpen"
|
|
39
|
+
size="xs"
|
|
40
|
+
variant="ghost"
|
|
41
|
+
icon="i-lucide-expand"
|
|
42
|
+
class="absolute top-1 right-1 z-10 opacity-70 hover:opacity-100"
|
|
43
|
+
title="Expand editor"
|
|
44
|
+
@click="isModalOpen = true"
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<UModal
|
|
49
|
+
v-model:open="isModalOpen"
|
|
50
|
+
title="Code Editor"
|
|
51
|
+
:fullscreen="fullscreen"
|
|
52
|
+
:ui="{ footer: 'justify-end' }"
|
|
53
|
+
>
|
|
54
|
+
<template #[slotName]>
|
|
55
|
+
<MonacoEditor
|
|
56
|
+
v-model="modelValue"
|
|
57
|
+
:lang="language"
|
|
58
|
+
:options="editorOptions"
|
|
59
|
+
class="rounded-md overflow-hidden border border-default"
|
|
60
|
+
:style="{
|
|
61
|
+
height: fullscreen ? 'calc(100vh - 200px)' : '480px'
|
|
62
|
+
}"
|
|
63
|
+
/>
|
|
64
|
+
<div v-if="slotName === 'content'">
|
|
65
|
+
<div class="flex justify-end">
|
|
66
|
+
<UButton @click="isModalOpen = false">
|
|
67
|
+
Close
|
|
68
|
+
</UButton>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</template>
|
|
72
|
+
<template #footer>
|
|
73
|
+
<UButton @click="isModalOpen = false">
|
|
74
|
+
Close
|
|
75
|
+
</UButton>
|
|
76
|
+
</template>
|
|
77
|
+
</UModal>
|
|
78
|
+
</div>
|
|
79
|
+
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
language?: string;
|
|
3
|
+
height?: string;
|
|
4
|
+
fullscreen?: boolean;
|
|
5
|
+
};
|
|
6
|
+
type __VLS_ModelProps = {
|
|
7
|
+
modelValue?: string;
|
|
8
|
+
};
|
|
9
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
10
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
14
|
+
}>, {
|
|
15
|
+
language: string;
|
|
16
|
+
height: string;
|
|
17
|
+
fullscreen: boolean;
|
|
18
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
|
+
declare const _default: typeof __VLS_export;
|
|
20
|
+
export default _default;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type Currency = {
|
|
2
|
+
name?: string;
|
|
3
|
+
code: string;
|
|
4
|
+
symbol: string;
|
|
5
|
+
};
|
|
6
|
+
type MoneyValue = {
|
|
7
|
+
currency: Currency['code'];
|
|
8
|
+
amount: number | null | undefined;
|
|
9
|
+
};
|
|
10
|
+
type __VLS_ModelProps = {
|
|
11
|
+
modelValue?: MoneyValue;
|
|
12
|
+
'amount'?: number | null | undefined;
|
|
13
|
+
'currency'?: string;
|
|
14
|
+
};
|
|
15
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
16
|
+
"update:modelValue": (value: MoneyValue) => any;
|
|
17
|
+
"update:amount": (value: number | null | undefined) => any;
|
|
18
|
+
"update:currency": (value: string | undefined) => any;
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
20
|
+
"onUpdate:modelValue"?: ((value: MoneyValue) => any) | undefined;
|
|
21
|
+
"onUpdate:amount"?: ((value: number | null | undefined) => any) | undefined;
|
|
22
|
+
"onUpdate:currency"?: ((value: string | undefined) => any) | undefined;
|
|
23
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
24
|
+
declare const _default: typeof __VLS_export;
|
|
25
|
+
export default _default;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { fromCents, toCents } from "#shared/utils/money.ts";
|
|
3
|
+
import { useCurrencies } from "~/store/queries/system.ts";
|
|
4
|
+
const model = defineModel({ type: Object, ...{
|
|
5
|
+
default: () => ({ currency: "EUR", amount: 0 })
|
|
6
|
+
} });
|
|
7
|
+
const amount = defineModel("amount", { type: null, ...{
|
|
8
|
+
get: () => fromCents(model.value?.amount),
|
|
9
|
+
set: (newValue) => model.value = { ...model.value, amount: toCents(newValue) }
|
|
10
|
+
} });
|
|
11
|
+
const currencyCode = defineModel("currency", { type: String, ...{
|
|
12
|
+
get: () => model.value?.currency || "EUR",
|
|
13
|
+
set: (newValue) => model.value = { ...model.value, currency: newValue }
|
|
14
|
+
} });
|
|
15
|
+
const { data: currencies, status } = useCurrencies();
|
|
16
|
+
const code = computed(() => currencyCode.value || "USD");
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<UFieldGroup class="w-full">
|
|
21
|
+
<USelectMenu
|
|
22
|
+
v-model="currencyCode"
|
|
23
|
+
:items="currencies"
|
|
24
|
+
value-key="code"
|
|
25
|
+
:search-input="{
|
|
26
|
+
placeholder: 'Search currency...',
|
|
27
|
+
icon: 'i-lucide-search',
|
|
28
|
+
loading: status === 'pending'
|
|
29
|
+
}"
|
|
30
|
+
:filter-fields="['name', 'code', 'symbol']"
|
|
31
|
+
:content="{ align: 'start' }"
|
|
32
|
+
:ui="{
|
|
33
|
+
base: 'pe-8',
|
|
34
|
+
content: 'w-48',
|
|
35
|
+
placeholder: 'hidden',
|
|
36
|
+
trailingIcon: 'size-4'
|
|
37
|
+
}"
|
|
38
|
+
trailing-icon="i-lucide-chevrons-up-down"
|
|
39
|
+
>
|
|
40
|
+
<span class="size-5 w-9 flex items-center text-lg">
|
|
41
|
+
{{ code }}
|
|
42
|
+
</span>
|
|
43
|
+
|
|
44
|
+
<template #item-label="{ item }">
|
|
45
|
+
{{ item.code }} ({{ item.symbol }})
|
|
46
|
+
</template>
|
|
47
|
+
</USelectMenu>
|
|
48
|
+
|
|
49
|
+
<UInputNumber
|
|
50
|
+
v-model="amount"
|
|
51
|
+
class="w-full"
|
|
52
|
+
placeholder="0.00"
|
|
53
|
+
:step="1"
|
|
54
|
+
:step-snapping="false"
|
|
55
|
+
:style="{ '--dial-code-length': `${code.length + 1.5}ch` }"
|
|
56
|
+
:ui="{
|
|
57
|
+
base: 'ps-(--dial-code-length)'
|
|
58
|
+
}"
|
|
59
|
+
:format-options="{
|
|
60
|
+
minimumFractionDigits: 2,
|
|
61
|
+
maximumFractionDigits: 2
|
|
62
|
+
}"
|
|
63
|
+
/>
|
|
64
|
+
</UFieldGroup>
|
|
65
|
+
</template>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type Currency = {
|
|
2
|
+
name?: string;
|
|
3
|
+
code: string;
|
|
4
|
+
symbol: string;
|
|
5
|
+
};
|
|
6
|
+
type MoneyValue = {
|
|
7
|
+
currency: Currency['code'];
|
|
8
|
+
amount: number | null | undefined;
|
|
9
|
+
};
|
|
10
|
+
type __VLS_ModelProps = {
|
|
11
|
+
modelValue?: MoneyValue;
|
|
12
|
+
'amount'?: number | null | undefined;
|
|
13
|
+
'currency'?: string;
|
|
14
|
+
};
|
|
15
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
16
|
+
"update:modelValue": (value: MoneyValue) => any;
|
|
17
|
+
"update:amount": (value: number | null | undefined) => any;
|
|
18
|
+
"update:currency": (value: string | undefined) => any;
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
20
|
+
"onUpdate:modelValue"?: ((value: MoneyValue) => any) | undefined;
|
|
21
|
+
"onUpdate:amount"?: ((value: number | null | undefined) => any) | undefined;
|
|
22
|
+
"onUpdate:currency"?: ((value: string | undefined) => any) | undefined;
|
|
23
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
24
|
+
declare const _default: typeof __VLS_export;
|
|
25
|
+
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type __VLS_ModelProps = {
|
|
2
|
+
modelValue?: boolean;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: boolean | undefined) => any;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
7
|
+
"onUpdate:modelValue"?: ((value: boolean | undefined) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type __VLS_ModelProps = {
|
|
2
|
+
modelValue?: boolean;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: boolean | undefined) => any;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
7
|
+
"onUpdate:modelValue"?: ((value: boolean | undefined) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
placeholder?: string;
|
|
3
|
+
searchPlaceholder?: string;
|
|
4
|
+
multiple?: boolean;
|
|
5
|
+
};
|
|
6
|
+
type __VLS_ModelProps = {
|
|
7
|
+
modelValue?: string[];
|
|
8
|
+
};
|
|
9
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
10
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
+
"update:modelValue": (value: string[]) => any;
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
+
"onUpdate:modelValue"?: ((value: string[]) => any) | undefined;
|
|
14
|
+
}>, {
|
|
15
|
+
placeholder: string;
|
|
16
|
+
searchPlaceholder: string;
|
|
17
|
+
multiple: boolean;
|
|
18
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
|
+
declare const _default: typeof __VLS_export;
|
|
20
|
+
export default _default;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
defineProps({
|
|
3
|
+
placeholder: { type: String, required: false, default: "Add tags..." },
|
|
4
|
+
searchPlaceholder: { type: String, required: false, default: "Type here to create a tag..." },
|
|
5
|
+
multiple: { type: Boolean, required: false, default: true }
|
|
6
|
+
});
|
|
7
|
+
const model = defineModel({ type: Array, ...{ default: () => [] } });
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<UInputTags
|
|
12
|
+
v-model="model"
|
|
13
|
+
:placeholder="placeholder"
|
|
14
|
+
/>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
placeholder?: string;
|
|
3
|
+
searchPlaceholder?: string;
|
|
4
|
+
multiple?: boolean;
|
|
5
|
+
};
|
|
6
|
+
type __VLS_ModelProps = {
|
|
7
|
+
modelValue?: string[];
|
|
8
|
+
};
|
|
9
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
10
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
+
"update:modelValue": (value: string[]) => any;
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
+
"onUpdate:modelValue"?: ((value: string[]) => any) | undefined;
|
|
14
|
+
}>, {
|
|
15
|
+
placeholder: string;
|
|
16
|
+
searchPlaceholder: string;
|
|
17
|
+
multiple: boolean;
|
|
18
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
|
+
declare const _default: typeof __VLS_export;
|
|
20
|
+
export default _default;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type __VLS_ModelProps = {
|
|
2
|
+
modelValue?: string;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
6
|
+
success: (args_0: string) => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
8
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
9
|
+
onSuccess?: ((args_0: string) => any) | undefined;
|
|
10
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const _default: typeof __VLS_export;
|
|
12
|
+
export default _default;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const modelValue = defineModel({ type: String });
|
|
3
|
+
const $emits = defineEmits(["success"]);
|
|
4
|
+
const errors = ref([]);
|
|
5
|
+
const model = computed({
|
|
6
|
+
get: () => modelValue.value,
|
|
7
|
+
set: (value) => {
|
|
8
|
+
modelValue.value = value;
|
|
9
|
+
errors.value = [];
|
|
10
|
+
if (!value) return;
|
|
11
|
+
if (!value.startsWith("http://") && !value.startsWith("https://")) {
|
|
12
|
+
errors.value.push(
|
|
13
|
+
"URL must start with http:// or https://"
|
|
14
|
+
);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
$emits("success", value);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<UInput
|
|
24
|
+
v-model="model"
|
|
25
|
+
type="url"
|
|
26
|
+
:errors="errors"
|
|
27
|
+
/>
|
|
28
|
+
</template>
|