@frigear-nu/ui 0.0.6 → 0.0.7
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/dist/module.mjs +0 -1
- package/dist/runtime/components/ConfirmDialog.d.vue.ts +2 -0
- package/dist/runtime/components/ConfirmDialog.vue +5 -3
- package/dist/runtime/components/ConfirmDialog.vue.d.ts +2 -0
- package/dist/runtime/components/global/CurrencyInput.d.vue.ts +7 -2
- package/dist/runtime/components/global/CurrencyInput.vue +9 -4
- package/dist/runtime/components/global/CurrencyInput.vue.d.ts +7 -2
- package/dist/runtime/components/global/MarkdownTextarea.d.vue.ts +23 -0
- package/dist/runtime/components/global/MarkdownTextarea.vue +73 -0
- package/dist/runtime/components/global/MarkdownTextarea.vue.d.ts +23 -0
- package/dist/runtime/components/global/MoneyInput.d.vue.ts +7 -7
- package/dist/runtime/components/global/MoneyInput.vue +10 -6
- package/dist/runtime/components/global/MoneyInput.vue.d.ts +7 -7
- package/dist/runtime/components/global/TranslatedInput.d.vue.ts +29 -0
- package/dist/runtime/components/global/TranslatedInput.vue +148 -0
- package/dist/runtime/components/global/TranslatedInput.vue.d.ts +29 -0
- package/dist/runtime/components/global/UrlInput.d.vue.ts +2 -2
- package/dist/runtime/components/global/UrlInput.vue.d.ts +2 -2
- package/dist/runtime/composables/index.d.ts +1 -0
- package/dist/runtime/composables/index.js +1 -0
- package/dist/runtime/composables/useConfirmDialog.d.ts +3 -0
- package/dist/runtime/composables/useTranslatedLocales.d.ts +8 -0
- package/dist/runtime/composables/useTranslatedLocales.js +24 -0
- package/dist/runtime/i18n/lang/da.json +12 -0
- package/dist/runtime/i18n/lang/en.json +12 -0
- package/dist/runtime/markdown.d.ts +10 -0
- package/dist/runtime/markdown.js +13 -0
- package/dist/runtime/shared/money.d.ts +15 -0
- package/dist/runtime/shared/money.js +31 -0
- package/dist/runtime/translated.d.ts +22 -0
- package/dist/runtime/translated.js +33 -0
- package/package.json +12 -13
- package/dist/runtime/components/Admin/AdminPageHeader.d.vue.ts +0 -21
- package/dist/runtime/components/Admin/AdminPageHeader.vue +0 -45
- package/dist/runtime/components/Admin/AdminPageHeader.vue.d.ts +0 -21
- package/dist/runtime/utils/table.d.ts +0 -11
- package/dist/runtime/utils/table.js +0 -23
package/dist/module.mjs
CHANGED
|
@@ -3,6 +3,8 @@ interface ConfirmDialogProps {
|
|
|
3
3
|
description?: string;
|
|
4
4
|
dismissible?: boolean;
|
|
5
5
|
confirmText?: string;
|
|
6
|
+
cancelText?: string;
|
|
7
|
+
destructive?: boolean;
|
|
6
8
|
}
|
|
7
9
|
declare const __VLS_export: import("vue").DefineComponent<ConfirmDialogProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
10
|
close: (value: boolean) => any;
|
|
@@ -3,7 +3,9 @@ defineProps({
|
|
|
3
3
|
title: { type: String, required: false },
|
|
4
4
|
description: { type: String, required: false },
|
|
5
5
|
dismissible: { type: Boolean, required: false, default: false },
|
|
6
|
-
confirmText: { type: String, required: false }
|
|
6
|
+
confirmText: { type: String, required: false },
|
|
7
|
+
cancelText: { type: String, required: false },
|
|
8
|
+
destructive: { type: Boolean, required: false }
|
|
7
9
|
});
|
|
8
10
|
const emits = defineEmits(["close"]);
|
|
9
11
|
</script>
|
|
@@ -17,14 +19,14 @@ const emits = defineEmits(["close"]);
|
|
|
17
19
|
>
|
|
18
20
|
<template #footer>
|
|
19
21
|
<UButton
|
|
20
|
-
label="Cancel"
|
|
22
|
+
:label="cancelText || 'Cancel'"
|
|
21
23
|
color="neutral"
|
|
22
24
|
variant="outline"
|
|
23
25
|
@click="emits('close', false)"
|
|
24
26
|
/>
|
|
25
27
|
<UButton
|
|
26
28
|
:label="confirmText || 'Confirm'"
|
|
27
|
-
color="neutral"
|
|
29
|
+
:color="destructive ? 'error' : 'neutral'"
|
|
28
30
|
@click="emits('close', true)"
|
|
29
31
|
/>
|
|
30
32
|
</template>
|
|
@@ -3,6 +3,8 @@ interface ConfirmDialogProps {
|
|
|
3
3
|
description?: string;
|
|
4
4
|
dismissible?: boolean;
|
|
5
5
|
confirmText?: string;
|
|
6
|
+
cancelText?: string;
|
|
7
|
+
destructive?: boolean;
|
|
6
8
|
}
|
|
7
9
|
declare const __VLS_export: import("vue").DefineComponent<ConfirmDialogProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
10
|
close: (value: boolean) => any;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import type { Currency } from '../../shared/money.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
currencies?: Currency[];
|
|
4
|
+
};
|
|
1
5
|
type __VLS_ModelProps = {
|
|
2
6
|
modelValue?: string;
|
|
3
7
|
};
|
|
4
|
-
|
|
8
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
10
|
"update:modelValue": (value: string) => any;
|
|
6
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
7
12
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
8
13
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
14
|
declare const _default: typeof __VLS_export;
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
2
|
+
import { currencyOptions } from "../../shared/money";
|
|
3
3
|
const currencyCode = defineModel({ type: String, ...{ default: "EUR" } });
|
|
4
|
-
const
|
|
5
|
-
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
currencies: { type: Array, required: false }
|
|
6
|
+
});
|
|
7
|
+
const nuxtApp = useNuxtApp();
|
|
8
|
+
const options = computed(() => props.currencies ?? currencyOptions(nuxtApp.$i18n?.locale?.value));
|
|
9
|
+
const status = "success";
|
|
10
|
+
const currency = computed(() => options.value.find((c) => c.code === currencyCode.value));
|
|
6
11
|
function onOpen() {
|
|
7
12
|
}
|
|
8
13
|
</script>
|
|
@@ -10,7 +15,7 @@ function onOpen() {
|
|
|
10
15
|
<template>
|
|
11
16
|
<USelectMenu
|
|
12
17
|
v-model="currencyCode"
|
|
13
|
-
:items="
|
|
18
|
+
:items="options"
|
|
14
19
|
value-key="code"
|
|
15
20
|
:search-input="{
|
|
16
21
|
placeholder: 'Search currency...',
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import type { Currency } from '../../shared/money.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
currencies?: Currency[];
|
|
4
|
+
};
|
|
1
5
|
type __VLS_ModelProps = {
|
|
2
6
|
modelValue?: string;
|
|
3
7
|
};
|
|
4
|
-
|
|
8
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
10
|
"update:modelValue": (value: string) => any;
|
|
6
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
7
12
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
8
13
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
14
|
declare const _default: typeof __VLS_export;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
placeholder?: string;
|
|
3
|
+
rows?: number;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
/** Show the Write / Preview toggle. */
|
|
7
|
+
preview?: boolean;
|
|
8
|
+
/** Render with MDC (Nuxt Content components like `::callout`) when the host app provides it. */
|
|
9
|
+
mdc?: boolean;
|
|
10
|
+
/** Variables for `{{ name }}` in MDC previews. */
|
|
11
|
+
mdcData?: Record<string, unknown>;
|
|
12
|
+
};
|
|
13
|
+
type __VLS_ModelProps = {
|
|
14
|
+
modelValue?: string;
|
|
15
|
+
};
|
|
16
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
17
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
18
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
20
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
21
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
|
+
declare const _default: typeof __VLS_export;
|
|
23
|
+
export default _default;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { renderMarkdown, withMdcData } from "../../markdown";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
placeholder: { type: String, required: false },
|
|
5
|
+
rows: { type: Number, required: false },
|
|
6
|
+
required: { type: Boolean, required: false },
|
|
7
|
+
disabled: { type: Boolean, required: false },
|
|
8
|
+
preview: { type: Boolean, required: false },
|
|
9
|
+
mdc: { type: Boolean, required: false },
|
|
10
|
+
mdcData: { type: Object, required: false }
|
|
11
|
+
});
|
|
12
|
+
const model = defineModel({ type: String });
|
|
13
|
+
const t = useUiT("markdown");
|
|
14
|
+
const previewing = ref(false);
|
|
15
|
+
const MdcComponent = resolveComponent("MDC");
|
|
16
|
+
const useMdc = computed(() => props.mdc && typeof MdcComponent !== "string");
|
|
17
|
+
const html = computed(() => renderMarkdown(model.value ?? ""));
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<div class="min-w-0 space-y-1">
|
|
22
|
+
<div
|
|
23
|
+
v-if="props.preview"
|
|
24
|
+
class="flex justify-end gap-1"
|
|
25
|
+
>
|
|
26
|
+
<UButton
|
|
27
|
+
size="xs"
|
|
28
|
+
color="neutral"
|
|
29
|
+
:variant="previewing ? 'ghost' : 'subtle'"
|
|
30
|
+
:label="t('write', 'Write')"
|
|
31
|
+
@click="previewing = false"
|
|
32
|
+
/>
|
|
33
|
+
<UButton
|
|
34
|
+
size="xs"
|
|
35
|
+
color="neutral"
|
|
36
|
+
:variant="previewing ? 'subtle' : 'ghost'"
|
|
37
|
+
icon="i-lucide-eye"
|
|
38
|
+
:label="t('preview', 'Preview')"
|
|
39
|
+
@click="previewing = true"
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
<!-- eslint-disable vue/no-v-html -- renderMarkdown escapes all input -->
|
|
43
|
+
<div
|
|
44
|
+
v-if="props.preview && previewing"
|
|
45
|
+
class="prose prose-sm min-h-16 max-w-none rounded-md border border-default p-2 text-muted"
|
|
46
|
+
:style="{ minHeight: `${(props.rows ?? 4) * 1.5}rem` }"
|
|
47
|
+
>
|
|
48
|
+
<span
|
|
49
|
+
v-if="!model?.trim()"
|
|
50
|
+
class="italic"
|
|
51
|
+
>{{ t("empty", "Nothing to preview") }}</span>
|
|
52
|
+
<component
|
|
53
|
+
:is="MdcComponent"
|
|
54
|
+
v-else-if="useMdc"
|
|
55
|
+
:value="withMdcData(model, mdcData)"
|
|
56
|
+
/>
|
|
57
|
+
<div
|
|
58
|
+
v-else
|
|
59
|
+
v-html="html"
|
|
60
|
+
/>
|
|
61
|
+
</div>
|
|
62
|
+
<!-- eslint-enable vue/no-v-html -->
|
|
63
|
+
<UTextarea
|
|
64
|
+
v-else
|
|
65
|
+
v-model="model"
|
|
66
|
+
:placeholder="placeholder"
|
|
67
|
+
:rows="rows"
|
|
68
|
+
:required="required"
|
|
69
|
+
:disabled="disabled"
|
|
70
|
+
class="w-full"
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
placeholder?: string;
|
|
3
|
+
rows?: number;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
/** Show the Write / Preview toggle. */
|
|
7
|
+
preview?: boolean;
|
|
8
|
+
/** Render with MDC (Nuxt Content components like `::callout`) when the host app provides it. */
|
|
9
|
+
mdc?: boolean;
|
|
10
|
+
/** Variables for `{{ name }}` in MDC previews. */
|
|
11
|
+
mdcData?: Record<string, unknown>;
|
|
12
|
+
};
|
|
13
|
+
type __VLS_ModelProps = {
|
|
14
|
+
modelValue?: string;
|
|
15
|
+
};
|
|
16
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
17
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
18
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
20
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
21
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
|
+
declare const _default: typeof __VLS_export;
|
|
23
|
+
export default _default;
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
type Currency
|
|
2
|
-
name?: string;
|
|
3
|
-
code: string;
|
|
4
|
-
symbol: string;
|
|
5
|
-
};
|
|
1
|
+
import type { Currency } from '../../shared/money.js';
|
|
6
2
|
type MoneyValue = {
|
|
7
3
|
currency: Currency['code'];
|
|
8
4
|
amount: number | null | undefined;
|
|
9
5
|
};
|
|
6
|
+
type __VLS_Props = {
|
|
7
|
+
currencies?: Currency[];
|
|
8
|
+
};
|
|
10
9
|
type __VLS_ModelProps = {
|
|
11
10
|
modelValue?: MoneyValue;
|
|
12
11
|
'amount'?: number | null | undefined;
|
|
13
12
|
'currency'?: string;
|
|
14
13
|
};
|
|
15
|
-
|
|
14
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
15
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
16
16
|
"update:modelValue": (value: MoneyValue) => any;
|
|
17
17
|
"update:amount": (value: number | null | undefined) => any;
|
|
18
18
|
"update:currency": (value: string | undefined) => any;
|
|
19
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
20
20
|
"onUpdate:modelValue"?: ((value: MoneyValue) => any) | undefined;
|
|
21
21
|
"onUpdate:amount"?: ((value: number | null | undefined) => any) | undefined;
|
|
22
22
|
"onUpdate:currency"?: ((value: string | undefined) => any) | undefined;
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { fromCents, toCents } from "
|
|
3
|
-
import { useCurrencies } from "~/store/queries/system.ts";
|
|
2
|
+
import { currencyOptions, fromCents, toCents } from "../../shared/money";
|
|
4
3
|
const model = defineModel({ type: Object, ...{
|
|
5
4
|
default: () => ({ currency: "EUR", amount: 0 })
|
|
6
5
|
} });
|
|
7
6
|
const amount = defineModel("amount", { type: null, ...{
|
|
8
|
-
get: () => fromCents(model.value?.amount),
|
|
9
|
-
set: (newValue) => model.value = { ...model.value, amount: toCents(newValue) }
|
|
7
|
+
get: () => fromCents(model.value?.amount, model.value?.currency || "EUR"),
|
|
8
|
+
set: (newValue) => model.value = { ...model.value, amount: toCents(newValue, model.value?.currency || "EUR") }
|
|
10
9
|
} });
|
|
11
10
|
const currencyCode = defineModel("currency", { type: String, ...{
|
|
12
11
|
get: () => model.value?.currency || "EUR",
|
|
13
12
|
set: (newValue) => model.value = { ...model.value, currency: newValue }
|
|
14
13
|
} });
|
|
15
|
-
const
|
|
14
|
+
const props = defineProps({
|
|
15
|
+
currencies: { type: Array, required: false }
|
|
16
|
+
});
|
|
17
|
+
const nuxtApp = useNuxtApp();
|
|
18
|
+
const options = computed(() => props.currencies ?? currencyOptions(nuxtApp.$i18n?.locale?.value));
|
|
19
|
+
const status = "success";
|
|
16
20
|
const code = computed(() => currencyCode.value || "USD");
|
|
17
21
|
</script>
|
|
18
22
|
|
|
@@ -20,7 +24,7 @@ const code = computed(() => currencyCode.value || "USD");
|
|
|
20
24
|
<UFieldGroup class="w-full">
|
|
21
25
|
<USelectMenu
|
|
22
26
|
v-model="currencyCode"
|
|
23
|
-
:items="
|
|
27
|
+
:items="options"
|
|
24
28
|
value-key="code"
|
|
25
29
|
:search-input="{
|
|
26
30
|
placeholder: 'Search currency...',
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
type Currency
|
|
2
|
-
name?: string;
|
|
3
|
-
code: string;
|
|
4
|
-
symbol: string;
|
|
5
|
-
};
|
|
1
|
+
import type { Currency } from '../../shared/money.js';
|
|
6
2
|
type MoneyValue = {
|
|
7
3
|
currency: Currency['code'];
|
|
8
4
|
amount: number | null | undefined;
|
|
9
5
|
};
|
|
6
|
+
type __VLS_Props = {
|
|
7
|
+
currencies?: Currency[];
|
|
8
|
+
};
|
|
10
9
|
type __VLS_ModelProps = {
|
|
11
10
|
modelValue?: MoneyValue;
|
|
12
11
|
'amount'?: number | null | undefined;
|
|
13
12
|
'currency'?: string;
|
|
14
13
|
};
|
|
15
|
-
|
|
14
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
15
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
16
16
|
"update:modelValue": (value: MoneyValue) => any;
|
|
17
17
|
"update:amount": (value: number | null | undefined) => any;
|
|
18
18
|
"update:currency": (value: string | undefined) => any;
|
|
19
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
20
20
|
"onUpdate:modelValue"?: ((value: MoneyValue) => any) | undefined;
|
|
21
21
|
"onUpdate:amount"?: ((value: number | null | undefined) => any) | undefined;
|
|
22
22
|
"onUpdate:currency"?: ((value: string | undefined) => any) | undefined;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Translated } from '../../translated.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
placeholder?: string;
|
|
4
|
+
/** Edit as a textarea (descriptions, markdown bodies). */
|
|
5
|
+
multiline?: boolean;
|
|
6
|
+
rows?: number;
|
|
7
|
+
/** Write / Preview toggle for multiline text (markdown). Defaults on. */
|
|
8
|
+
preview?: boolean;
|
|
9
|
+
/** Preview with MDC (components such as `::callout`) instead of plain markdown. */
|
|
10
|
+
mdc?: boolean;
|
|
11
|
+
/** Variables for `{{ name }}` in the MDC preview. */
|
|
12
|
+
mdcData?: Record<string, unknown>;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
};
|
|
16
|
+
type __VLS_ModelProps = {
|
|
17
|
+
/** Either one string for every language, or a map of locale -> text. `undefined` / `null` = empty. */
|
|
18
|
+
modelValue?: Translated | null | undefined;
|
|
19
|
+
};
|
|
20
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
21
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
22
|
+
"update:modelValue": (value: Translated | null | undefined) => any;
|
|
23
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
24
|
+
"onUpdate:modelValue"?: ((value: Translated | null | undefined) => any) | undefined;
|
|
25
|
+
}>, {
|
|
26
|
+
preview: boolean;
|
|
27
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
|
+
declare const _default: typeof __VLS_export;
|
|
29
|
+
export default _default;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { collapseTranslated, expandTranslated, filledLocales, isLocaleCode, readTranslated, translate, writeTranslated } from "../../translated";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
placeholder: { type: String, required: false },
|
|
5
|
+
multiline: { type: Boolean, required: false },
|
|
6
|
+
rows: { type: Number, required: false },
|
|
7
|
+
preview: { type: Boolean, required: false, default: true },
|
|
8
|
+
mdc: { type: Boolean, required: false },
|
|
9
|
+
mdcData: { type: Object, required: false },
|
|
10
|
+
required: { type: Boolean, required: false },
|
|
11
|
+
disabled: { type: Boolean, required: false }
|
|
12
|
+
});
|
|
13
|
+
const model = defineModel({ type: null });
|
|
14
|
+
const t = useUiT("translated");
|
|
15
|
+
const current = useTranslatedLocale();
|
|
16
|
+
const available = useTranslatedLocales();
|
|
17
|
+
const fallback = useTranslatedFallbackLocale();
|
|
18
|
+
const translated = computed(() => !!model.value && typeof model.value === "object");
|
|
19
|
+
const added = ref([]);
|
|
20
|
+
const newLocale = ref("");
|
|
21
|
+
const locales = computed(() => [.../* @__PURE__ */ new Set([...available.value, ...filledLocales(model.value), ...added.value])]);
|
|
22
|
+
const filled = computed(() => new Set(filledLocales(model.value)));
|
|
23
|
+
const fallbackText = (locale) => translate(model.value, locale, fallback.value);
|
|
24
|
+
function addLocale() {
|
|
25
|
+
const code = newLocale.value.trim();
|
|
26
|
+
if (isLocaleCode(code) && !locales.value.includes(code)) added.value.push(code);
|
|
27
|
+
newLocale.value = "";
|
|
28
|
+
}
|
|
29
|
+
function toggle() {
|
|
30
|
+
model.value = translated.value ? collapseTranslated(model.value, current.value) : expandTranslated(model.value, current.value) ?? {};
|
|
31
|
+
}
|
|
32
|
+
function setPlain(text) {
|
|
33
|
+
model.value = text || void 0;
|
|
34
|
+
}
|
|
35
|
+
function setLocale(locale, text) {
|
|
36
|
+
model.value = writeTranslated({ ...model.value }, locale, text) ?? {};
|
|
37
|
+
}
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<template>
|
|
41
|
+
<div class="w-full space-y-1">
|
|
42
|
+
<div
|
|
43
|
+
v-if="!translated"
|
|
44
|
+
class="flex items-start gap-1"
|
|
45
|
+
>
|
|
46
|
+
<MarkdownTextarea
|
|
47
|
+
v-if="props.multiline"
|
|
48
|
+
:model-value="readTranslated(model, current)"
|
|
49
|
+
:placeholder="placeholder"
|
|
50
|
+
:rows="rows ?? 4"
|
|
51
|
+
:required="required"
|
|
52
|
+
:disabled="disabled"
|
|
53
|
+
:preview="preview"
|
|
54
|
+
:mdc="mdc"
|
|
55
|
+
:mdc-data="mdcData"
|
|
56
|
+
class="min-w-0 flex-1"
|
|
57
|
+
@update:model-value="setPlain(String($event))"
|
|
58
|
+
/>
|
|
59
|
+
<UInput
|
|
60
|
+
v-else
|
|
61
|
+
:model-value="readTranslated(model, current)"
|
|
62
|
+
:placeholder="placeholder"
|
|
63
|
+
:required="required"
|
|
64
|
+
:disabled="disabled"
|
|
65
|
+
class="min-w-0 flex-1"
|
|
66
|
+
@update:model-value="setPlain(String($event))"
|
|
67
|
+
/>
|
|
68
|
+
<UButton
|
|
69
|
+
color="neutral"
|
|
70
|
+
variant="outline"
|
|
71
|
+
icon="i-lucide-languages"
|
|
72
|
+
:disabled="disabled"
|
|
73
|
+
:aria-label="t('translate', 'Translate')"
|
|
74
|
+
:title="t('translate', 'Translate')"
|
|
75
|
+
@click="toggle"
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div
|
|
80
|
+
v-else
|
|
81
|
+
class="space-y-1 rounded-md border border-default p-1.5"
|
|
82
|
+
>
|
|
83
|
+
<div
|
|
84
|
+
v-for="locale in locales"
|
|
85
|
+
:key="locale"
|
|
86
|
+
class="flex items-start gap-1.5"
|
|
87
|
+
>
|
|
88
|
+
<UBadge
|
|
89
|
+
:color="filled.has(locale) ? 'primary' : 'neutral'"
|
|
90
|
+
:variant="filled.has(locale) ? 'subtle' : 'outline'"
|
|
91
|
+
:icon="filled.has(locale) ? 'i-lucide-check' : void 0"
|
|
92
|
+
size="sm"
|
|
93
|
+
class="mt-1.5 min-w-11 justify-center uppercase"
|
|
94
|
+
:title="filled.has(locale) ? t('filled', 'Translated') : t('missing', 'Missing, shows the fallback language')"
|
|
95
|
+
:label="locale"
|
|
96
|
+
/>
|
|
97
|
+
<MarkdownTextarea
|
|
98
|
+
v-if="props.multiline"
|
|
99
|
+
:model-value="readTranslated(model, locale)"
|
|
100
|
+
:placeholder="fallbackText(locale) || placeholder"
|
|
101
|
+
:rows="rows ?? 3"
|
|
102
|
+
:disabled="disabled"
|
|
103
|
+
:preview="preview"
|
|
104
|
+
:mdc="mdc"
|
|
105
|
+
:mdc-data="mdcData"
|
|
106
|
+
class="min-w-0 flex-1"
|
|
107
|
+
@update:model-value="setLocale(locale, String($event))"
|
|
108
|
+
/>
|
|
109
|
+
<UInput
|
|
110
|
+
v-else
|
|
111
|
+
:model-value="readTranslated(model, locale)"
|
|
112
|
+
:placeholder="fallbackText(locale) || placeholder"
|
|
113
|
+
:disabled="disabled"
|
|
114
|
+
class="min-w-0 flex-1"
|
|
115
|
+
@update:model-value="setLocale(locale, String($event))"
|
|
116
|
+
/>
|
|
117
|
+
</div>
|
|
118
|
+
<form
|
|
119
|
+
class="flex gap-1"
|
|
120
|
+
@submit.prevent="addLocale"
|
|
121
|
+
>
|
|
122
|
+
<UInput
|
|
123
|
+
v-model="newLocale"
|
|
124
|
+
size="xs"
|
|
125
|
+
:placeholder="t('addLanguage', 'Add language, e.g. de')"
|
|
126
|
+
class="min-w-0 flex-1"
|
|
127
|
+
/>
|
|
128
|
+
<UButton
|
|
129
|
+
type="submit"
|
|
130
|
+
color="neutral"
|
|
131
|
+
variant="outline"
|
|
132
|
+
size="xs"
|
|
133
|
+
icon="i-lucide-plus"
|
|
134
|
+
:aria-label="t('addLanguage', 'Add language, e.g. de')"
|
|
135
|
+
/>
|
|
136
|
+
</form>
|
|
137
|
+
<UButton
|
|
138
|
+
color="neutral"
|
|
139
|
+
variant="link"
|
|
140
|
+
size="xs"
|
|
141
|
+
icon="i-lucide-x"
|
|
142
|
+
:disabled="disabled"
|
|
143
|
+
:label="t('singleLanguage', 'Same text in every language')"
|
|
144
|
+
@click="toggle"
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</template>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Translated } from '../../translated.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
placeholder?: string;
|
|
4
|
+
/** Edit as a textarea (descriptions, markdown bodies). */
|
|
5
|
+
multiline?: boolean;
|
|
6
|
+
rows?: number;
|
|
7
|
+
/** Write / Preview toggle for multiline text (markdown). Defaults on. */
|
|
8
|
+
preview?: boolean;
|
|
9
|
+
/** Preview with MDC (components such as `::callout`) instead of plain markdown. */
|
|
10
|
+
mdc?: boolean;
|
|
11
|
+
/** Variables for `{{ name }}` in the MDC preview. */
|
|
12
|
+
mdcData?: Record<string, unknown>;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
};
|
|
16
|
+
type __VLS_ModelProps = {
|
|
17
|
+
/** Either one string for every language, or a map of locale -> text. `undefined` / `null` = empty. */
|
|
18
|
+
modelValue?: Translated | null | undefined;
|
|
19
|
+
};
|
|
20
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
21
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
22
|
+
"update:modelValue": (value: Translated | null | undefined) => any;
|
|
23
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
24
|
+
"onUpdate:modelValue"?: ((value: Translated | null | undefined) => any) | undefined;
|
|
25
|
+
}>, {
|
|
26
|
+
preview: boolean;
|
|
27
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
|
+
declare const _default: typeof __VLS_export;
|
|
29
|
+
export default _default;
|
|
@@ -2,11 +2,11 @@ type __VLS_ModelProps = {
|
|
|
2
2
|
modelValue?: string;
|
|
3
3
|
};
|
|
4
4
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
-
"update:modelValue": (value: string | undefined) => any;
|
|
6
5
|
success: (args_0: string) => any;
|
|
6
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
7
7
|
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
8
|
-
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
9
8
|
onSuccess?: ((args_0: string) => any) | undefined;
|
|
9
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
10
10
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
11
|
declare const _default: typeof __VLS_export;
|
|
12
12
|
export default _default;
|
|
@@ -2,11 +2,11 @@ type __VLS_ModelProps = {
|
|
|
2
2
|
modelValue?: string;
|
|
3
3
|
};
|
|
4
4
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
-
"update:modelValue": (value: string | undefined) => any;
|
|
6
5
|
success: (args_0: string) => any;
|
|
6
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
7
7
|
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
8
|
-
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
9
8
|
onSuccess?: ((args_0: string) => any) | undefined;
|
|
9
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
10
10
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
11
|
declare const _default: typeof __VLS_export;
|
|
12
12
|
export default _default;
|
|
@@ -2,5 +2,8 @@ export interface ConfirmDialogOptions {
|
|
|
2
2
|
title: string;
|
|
3
3
|
description?: string;
|
|
4
4
|
confirmText?: string;
|
|
5
|
+
cancelText?: string;
|
|
6
|
+
/** Style the confirm button as destructive. */
|
|
7
|
+
destructive?: boolean;
|
|
5
8
|
}
|
|
6
9
|
export declare const useConfirmDialog: () => (options: ConfirmDialogOptions) => Promise<boolean>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Locale of the visitor: `@nuxtjs/i18n`'s when installed, otherwise `en`. */
|
|
2
|
+
export declare function useTranslatedLocale(): any;
|
|
3
|
+
/** Locales content can be translated into: the configured `@nuxtjs/i18n` ones when installed, otherwise just `en`. */
|
|
4
|
+
export declare function useTranslatedLocales(): any;
|
|
5
|
+
/** The site's default locale, used when a text has no translation for the current one. */
|
|
6
|
+
export declare function useTranslatedFallbackLocale(): any;
|
|
7
|
+
/** Optional-i18n translator for this package's own messages (`translated.*`), falling back to the English default. */
|
|
8
|
+
export declare function useUiT(namespace: string): (key: string, fallback: string, params?: Record<string, string | number>) => string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const i18n = () => useNuxtApp().$i18n;
|
|
2
|
+
export function useTranslatedLocale() {
|
|
3
|
+
const nuxtApp = i18n();
|
|
4
|
+
return computed(() => nuxtApp?.locale?.value ?? "en");
|
|
5
|
+
}
|
|
6
|
+
export function useTranslatedLocales() {
|
|
7
|
+
const nuxtApp = i18n();
|
|
8
|
+
return computed(() => {
|
|
9
|
+
const codes = (nuxtApp?.locales?.value ?? []).map((locale) => typeof locale === "string" ? locale : locale.code);
|
|
10
|
+
return codes.length ? codes : ["en"];
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export function useTranslatedFallbackLocale() {
|
|
14
|
+
const nuxtApp = i18n();
|
|
15
|
+
return computed(() => nuxtApp?.defaultLocale ?? "en");
|
|
16
|
+
}
|
|
17
|
+
export function useUiT(namespace) {
|
|
18
|
+
const nuxtApp = useNuxtApp().$i18n;
|
|
19
|
+
return (key, fallback, params = {}) => {
|
|
20
|
+
const path = `${namespace}.${key}`;
|
|
21
|
+
if (nuxtApp?.te?.(path)) return nuxtApp.t(path, params);
|
|
22
|
+
return Object.entries(params).reduce((text, [name, value]) => text.replaceAll(`{${name}}`, String(value)), fallback);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -21,5 +21,17 @@
|
|
|
21
21
|
},
|
|
22
22
|
"locale": {
|
|
23
23
|
"switch": "Vælg sprog (nu: {name})"
|
|
24
|
+
},
|
|
25
|
+
"translated": {
|
|
26
|
+
"translate": "Oversæt",
|
|
27
|
+
"filled": "Oversat",
|
|
28
|
+
"missing": "Mangler, viser reserve-sproget",
|
|
29
|
+
"addLanguage": "Tilføj sprog, f.eks. de",
|
|
30
|
+
"singleLanguage": "Samme tekst på alle sprog"
|
|
31
|
+
},
|
|
32
|
+
"markdown": {
|
|
33
|
+
"write": "Skriv",
|
|
34
|
+
"preview": "Vis",
|
|
35
|
+
"empty": "Intet at vise"
|
|
24
36
|
}
|
|
25
37
|
}
|
|
@@ -21,5 +21,17 @@
|
|
|
21
21
|
},
|
|
22
22
|
"locale": {
|
|
23
23
|
"switch": "Choose language (now: {name})"
|
|
24
|
+
},
|
|
25
|
+
"translated": {
|
|
26
|
+
"translate": "Translate",
|
|
27
|
+
"filled": "Translated",
|
|
28
|
+
"missing": "Missing, shows the fallback language",
|
|
29
|
+
"addLanguage": "Add language, e.g. de",
|
|
30
|
+
"singleLanguage": "Same text in every language"
|
|
31
|
+
},
|
|
32
|
+
"markdown": {
|
|
33
|
+
"write": "Write",
|
|
34
|
+
"preview": "Preview",
|
|
35
|
+
"empty": "Nothing to preview"
|
|
24
36
|
}
|
|
25
37
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny, safe renderer for `markdown` fields: escapes everything, then supports `**bold**`,
|
|
3
|
+
* `_italic_`, `[text](https://…)` links and blank-line separated paragraphs.
|
|
4
|
+
*/
|
|
5
|
+
export declare function renderMarkdown(source: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Prepends `data` as frontmatter so MDC (`<MDC :value>`) can resolve `{{ name }}` in the text.
|
|
8
|
+
* JSON values are valid YAML, which keeps quoting safe for arbitrary strings.
|
|
9
|
+
*/
|
|
10
|
+
export declare function withMdcData(source: string, data?: Record<string, unknown>): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const escape = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
2
|
+
const safeHref = (href) => /^(?:https?:\/\/|\/(?![/\\])|mailto:)/.test(href);
|
|
3
|
+
export function renderMarkdown(source) {
|
|
4
|
+
return source.split(/\n{2,}/).map((paragraph) => escape(paragraph.trim()).replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/\b_(.+?)_\b/g, "<em>$1</em>").replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, (match, label, href) => safeHref(href.replace(/&/g, "&")) ? `<a href="${href}" target="_blank" rel="noopener" class="underline">${label}</a>` : match).replace(/\n/g, "<br>")).filter(Boolean).map((paragraph) => `<p>${paragraph}</p>`).join("");
|
|
5
|
+
}
|
|
6
|
+
export function withMdcData(source, data) {
|
|
7
|
+
const entries = Object.entries(data ?? {}).filter(([, value]) => value !== void 0);
|
|
8
|
+
if (!entries.length) return source;
|
|
9
|
+
return `---
|
|
10
|
+
${entries.map(([key, value]) => `${JSON.stringify(key)}: ${JSON.stringify(value)}`).join("\n")}
|
|
11
|
+
---
|
|
12
|
+
${source}`;
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type Currency = {
|
|
2
|
+
name?: string;
|
|
3
|
+
code: string;
|
|
4
|
+
symbol: string;
|
|
5
|
+
};
|
|
6
|
+
/** The number of minor-unit digits of a currency (2 for EUR, 0 for JPY, 3 for KWD), from `Intl`. */
|
|
7
|
+
export declare function currencyDigits(code: string): number;
|
|
8
|
+
/** Formats an amount in a currency's minor unit (cents, øre) for display, e.g. `formatMoney(15000, 'DKK', 'da')` -> `150,00 kr.`. */
|
|
9
|
+
export declare function formatMoney(amount: number, currency: string, locale?: string): string;
|
|
10
|
+
/** Minor units (cents) to the major-unit number shown in an input. */
|
|
11
|
+
export declare function fromCents(amount: number | null | undefined, code?: string): number | null | undefined;
|
|
12
|
+
/** The major-unit number from an input to minor units (cents), rounded to whole minor units. */
|
|
13
|
+
export declare function toCents(value: number | null | undefined, code?: string): number | null | undefined;
|
|
14
|
+
/** Every ISO currency the runtime knows, with its localized name and symbol, sorted by code. */
|
|
15
|
+
export declare function currencyOptions(locale?: string): Currency[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function currencyDigits(code) {
|
|
2
|
+
try {
|
|
3
|
+
return new Intl.NumberFormat("en", { style: "currency", currency: code }).resolvedOptions().maximumFractionDigits ?? 2;
|
|
4
|
+
} catch {
|
|
5
|
+
return 2;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export function formatMoney(amount, currency, locale) {
|
|
9
|
+
const code = currency.toUpperCase();
|
|
10
|
+
try {
|
|
11
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency: code }).format(amount / 10 ** currencyDigits(code));
|
|
12
|
+
} catch {
|
|
13
|
+
return `${(amount / 100).toFixed(2)} ${code}`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function fromCents(amount, code = "EUR") {
|
|
17
|
+
if (amount === null || amount === void 0) return amount;
|
|
18
|
+
return amount / 10 ** currencyDigits(code);
|
|
19
|
+
}
|
|
20
|
+
export function toCents(value, code = "EUR") {
|
|
21
|
+
if (value === null || value === void 0 || Number.isNaN(value)) return null;
|
|
22
|
+
return Math.round(value * 10 ** currencyDigits(code));
|
|
23
|
+
}
|
|
24
|
+
export function currencyOptions(locale = "en") {
|
|
25
|
+
const codes = typeof Intl.supportedValuesOf === "function" ? Intl.supportedValuesOf("currency") : ["EUR", "USD", "GBP", "DKK", "SEK", "NOK"];
|
|
26
|
+
const names = new Intl.DisplayNames([locale], { type: "currency" });
|
|
27
|
+
return codes.map((code) => {
|
|
28
|
+
const symbol = new Intl.NumberFormat(locale, { style: "currency", currency: code, currencyDisplay: "narrowSymbol" }).formatToParts(0).find((part) => part.type === "currency")?.value ?? code;
|
|
29
|
+
return { code, symbol, name: names.of(code) ?? code };
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** A text that is either one string for every language, or a map of locale -> text. */
|
|
2
|
+
export type Translated = string | Record<string, string>;
|
|
3
|
+
/**
|
|
4
|
+
* Picks the text to show for `locale`: that locale, else `fallback` (the site's default locale), else `en`,
|
|
5
|
+
* else the first entry that has text. Empty entries never win, so a half-translated value shows another language
|
|
6
|
+
* instead of nothing.
|
|
7
|
+
*/
|
|
8
|
+
export declare function translate(value: Translated | null | undefined, locale?: string, fallback?: string): string;
|
|
9
|
+
/** True when `value` holds text for exactly that locale (no fallback). */
|
|
10
|
+
export declare function hasTranslation(value: Translated | null | undefined, locale: string): boolean;
|
|
11
|
+
/** Reads the text for one locale out of a translatable value; a plain string counts as the text of every locale. */
|
|
12
|
+
export declare function readTranslated(value: Translated | null | undefined, locale: string): string;
|
|
13
|
+
/** Writes the text for one locale; plain strings stay plain, per-locale maps keep their other locales. Empty entries are dropped. */
|
|
14
|
+
export declare function writeTranslated(value: Translated | null | undefined, locale: string, text: string): Translated | undefined;
|
|
15
|
+
/** A plain string becomes a per-locale map holding that text for `locale`. */
|
|
16
|
+
export declare function expandTranslated(value: Translated | null | undefined, locale: string): Translated | undefined;
|
|
17
|
+
/** A per-locale map becomes one plain string: the text of `locale`, else `en`, else the first one written. */
|
|
18
|
+
export declare function collapseTranslated(value: Translated | null | undefined, locale: string): Translated | undefined;
|
|
19
|
+
/** The locales of a value that actually have text. */
|
|
20
|
+
export declare function filledLocales(value: Translated | null | undefined): string[];
|
|
21
|
+
/** Accepts `da`, `en-GB`, `pt_BR`... */
|
|
22
|
+
export declare const isLocaleCode: (code: string) => boolean;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function translate(value, locale = "en", fallback) {
|
|
2
|
+
if (!value) return "";
|
|
3
|
+
if (typeof value === "string") return value;
|
|
4
|
+
return value[locale] || (fallback ? value[fallback] : "") || value.en || Object.values(value).find(Boolean) || "";
|
|
5
|
+
}
|
|
6
|
+
export function hasTranslation(value, locale) {
|
|
7
|
+
return !!value && (typeof value === "string" ? false : !!value[locale]);
|
|
8
|
+
}
|
|
9
|
+
export function readTranslated(value, locale) {
|
|
10
|
+
if (!value) return "";
|
|
11
|
+
if (typeof value === "string") return value;
|
|
12
|
+
return value[locale] ?? "";
|
|
13
|
+
}
|
|
14
|
+
export function writeTranslated(value, locale, text) {
|
|
15
|
+
if (value && typeof value === "object") {
|
|
16
|
+
const next = Object.fromEntries(Object.entries({ ...value, [locale]: text }).filter(([, entry]) => entry));
|
|
17
|
+
return Object.keys(next).length ? next : void 0;
|
|
18
|
+
}
|
|
19
|
+
return text || void 0;
|
|
20
|
+
}
|
|
21
|
+
export function expandTranslated(value, locale) {
|
|
22
|
+
if (typeof value !== "string") return value ?? void 0;
|
|
23
|
+
return value ? { [locale]: value } : void 0;
|
|
24
|
+
}
|
|
25
|
+
export function collapseTranslated(value, locale) {
|
|
26
|
+
if (!value) return void 0;
|
|
27
|
+
if (typeof value === "string") return value;
|
|
28
|
+
return value[locale] || value.en || Object.values(value).find(Boolean) || void 0;
|
|
29
|
+
}
|
|
30
|
+
export function filledLocales(value) {
|
|
31
|
+
return value && typeof value === "object" ? Object.keys(value).filter((code) => value[code]) : [];
|
|
32
|
+
}
|
|
33
|
+
export const isLocaleCode = (code) => /^[a-z]{2,3}(?:[-_][a-z0-9]{2,8})*$/i.test(code);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frigear-nu/ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Shared UI components and composables for Frigear Nuxt applications, built on Nuxt UI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://docs.frigear.dev/modules/ui",
|
|
@@ -19,7 +19,10 @@
|
|
|
19
19
|
},
|
|
20
20
|
"./components/*": "./dist/runtime/components/global/*.vue",
|
|
21
21
|
"./composables": "./dist/runtime/composables/index.js",
|
|
22
|
-
"./composables/*": "./dist/runtime/composables/*.js"
|
|
22
|
+
"./composables/*": "./dist/runtime/composables/*.js",
|
|
23
|
+
"./translated": "./dist/runtime/translated.js",
|
|
24
|
+
"./markdown": "./dist/runtime/markdown.js",
|
|
25
|
+
"./money": "./dist/runtime/shared/money.js"
|
|
23
26
|
},
|
|
24
27
|
"main": "./dist/module.mjs",
|
|
25
28
|
"workspaces": [
|
|
@@ -31,25 +34,21 @@
|
|
|
31
34
|
"dependencies": {
|
|
32
35
|
"@nuxt/kit": "^4.6.0",
|
|
33
36
|
"@vueuse/core": "^13.5.0",
|
|
34
|
-
"cron-parser": "^5.10.0",
|
|
35
37
|
"defu": "^6.1.4",
|
|
36
|
-
"yaml": "^2.7.1",
|
|
37
38
|
"nuxt-monaco-editor": "^1.4.1",
|
|
38
|
-
"monaco-editor": "^0.56.0"
|
|
39
|
-
"@tanstack/vue-table": "^8.21.3",
|
|
40
|
-
"scule": "^1.3.0",
|
|
41
|
-
"tailwindcss": "^4.3.3"
|
|
39
|
+
"monaco-editor": "^0.56.0"
|
|
42
40
|
},
|
|
43
41
|
"devDependencies": {
|
|
42
|
+
"@frigear-nu/eslint-config": "0.0.2",
|
|
43
|
+
"@nuxt/module-builder": "^1.0.3",
|
|
44
|
+
"@nuxt/schema": "^4.6.0",
|
|
44
45
|
"@nuxt/ui": "^4.10.0",
|
|
45
|
-
"@frigear-nu/eslint-config": "0.0.0",
|
|
46
46
|
"eslint": "^10.8.1",
|
|
47
47
|
"nuxt": "^4.6.1",
|
|
48
|
-
"
|
|
49
|
-
"@nuxt/module-builder": "^1.0.3",
|
|
48
|
+
"tailwindcss": "^4.3.3",
|
|
50
49
|
"typescript": "^6.0.3",
|
|
51
|
-
"
|
|
52
|
-
"
|
|
50
|
+
"vitest": "^5.0.0",
|
|
51
|
+
"vue-tsc": "^3.3.11"
|
|
53
52
|
},
|
|
54
53
|
"peerDependencies": {
|
|
55
54
|
"@nuxt/ui": "^4.10.0",
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { ButtonProps, PageHeaderProps } from '@nuxt/ui';
|
|
2
|
-
type Props = PageHeaderProps & {
|
|
3
|
-
returnButton?: ButtonProps | false;
|
|
4
|
-
};
|
|
5
|
-
declare var __VLS_9: {}, __VLS_18: string, __VLS_19: {};
|
|
6
|
-
type __VLS_Slots = {} & {
|
|
7
|
-
[K in NonNullable<typeof __VLS_18>]?: (props: typeof __VLS_19) => any;
|
|
8
|
-
} & {
|
|
9
|
-
headline?: (props: typeof __VLS_9) => any;
|
|
10
|
-
};
|
|
11
|
-
declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
12
|
-
returnButton: ButtonProps | false;
|
|
13
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
-
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
15
|
-
declare const _default: typeof __VLS_export;
|
|
16
|
-
export default _default;
|
|
17
|
-
type __VLS_WithSlots<T, S> = T & {
|
|
18
|
-
new (): {
|
|
19
|
-
$slots: S;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { objectOmit } from "@vueuse/core";
|
|
3
|
-
defineProps({
|
|
4
|
-
as: { type: null, required: false },
|
|
5
|
-
headline: { type: String, required: false },
|
|
6
|
-
title: { type: String, required: false },
|
|
7
|
-
description: { type: String, required: false },
|
|
8
|
-
links: { type: Array, required: false },
|
|
9
|
-
class: { type: null, required: false },
|
|
10
|
-
ui: { type: Object, required: false },
|
|
11
|
-
returnButton: { type: [Object, Boolean], required: false, default: () => ({
|
|
12
|
-
label: "Admin",
|
|
13
|
-
to: "/admin",
|
|
14
|
-
icon: "i-lucide-arrow-left",
|
|
15
|
-
variant: "link"
|
|
16
|
-
}) }
|
|
17
|
-
});
|
|
18
|
-
const forwardedSlots = ["links", "description"];
|
|
19
|
-
</script>
|
|
20
|
-
|
|
21
|
-
<template>
|
|
22
|
-
<UPageHeader
|
|
23
|
-
v-bind="objectOmit($props, ['returnButton'])"
|
|
24
|
-
:ui="{ headline: 'flex-1 p-0' }"
|
|
25
|
-
>
|
|
26
|
-
<!-- Manually handled slot -->
|
|
27
|
-
<template #headline>
|
|
28
|
-
<slot name="headline">
|
|
29
|
-
<UButton
|
|
30
|
-
v-if="returnButton !== false && returnButton !== void 0"
|
|
31
|
-
class="p-0"
|
|
32
|
-
v-bind="{ variant: 'link', ...returnButton }"
|
|
33
|
-
/>
|
|
34
|
-
</slot>
|
|
35
|
-
</template>
|
|
36
|
-
|
|
37
|
-
<template
|
|
38
|
-
v-for="slotName in forwardedSlots"
|
|
39
|
-
:key="slotName"
|
|
40
|
-
#[slotName]
|
|
41
|
-
>
|
|
42
|
-
<slot :name="slotName" />
|
|
43
|
-
</template>
|
|
44
|
-
</UPageHeader>
|
|
45
|
-
</template>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { ButtonProps, PageHeaderProps } from '@nuxt/ui';
|
|
2
|
-
type Props = PageHeaderProps & {
|
|
3
|
-
returnButton?: ButtonProps | false;
|
|
4
|
-
};
|
|
5
|
-
declare var __VLS_9: {}, __VLS_18: string, __VLS_19: {};
|
|
6
|
-
type __VLS_Slots = {} & {
|
|
7
|
-
[K in NonNullable<typeof __VLS_18>]?: (props: typeof __VLS_19) => any;
|
|
8
|
-
} & {
|
|
9
|
-
headline?: (props: typeof __VLS_9) => any;
|
|
10
|
-
};
|
|
11
|
-
declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
12
|
-
returnButton: ButtonProps | false;
|
|
13
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
-
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
15
|
-
declare const _default: typeof __VLS_export;
|
|
16
|
-
export default _default;
|
|
17
|
-
type __VLS_WithSlots<T, S> = T & {
|
|
18
|
-
new (): {
|
|
19
|
-
$slots: S;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { TableColumn, DropdownMenuItem } from '@nuxt/ui';
|
|
2
|
-
import type { Row } from '@tanstack/vue-table';
|
|
3
|
-
export type ColumnDefinerProps<T, TData = TableColumn<T>> = Partial<Omit<TData, 'id'>> & Pick<TData, 'id'>;
|
|
4
|
-
export declare const defineColumn: <Type = unknown, TData = TableColumn<Type>>(columnDef: ColumnDefinerProps<Type, TData> | string) => TData;
|
|
5
|
-
type RowAction<T> = Omit<DropdownMenuItem, 'onSelect'> & {
|
|
6
|
-
onSelect: (row: Row<T>) => void | Promise<void>;
|
|
7
|
-
};
|
|
8
|
-
export declare const defineRowActions: <T>(row: Row<T>, action: RowAction<T>) => {
|
|
9
|
-
onSelect: () => void | Promise<void>;
|
|
10
|
-
};
|
|
11
|
-
export {};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import defu from "defu";
|
|
2
|
-
import { titleCase } from "scule";
|
|
3
|
-
export const defineColumn = (columnDef) => {
|
|
4
|
-
let def;
|
|
5
|
-
if (typeof columnDef !== "object") {
|
|
6
|
-
def = {
|
|
7
|
-
id: columnDef
|
|
8
|
-
};
|
|
9
|
-
} else {
|
|
10
|
-
def = columnDef;
|
|
11
|
-
}
|
|
12
|
-
return defu(def, {
|
|
13
|
-
id: crypto.randomUUID(),
|
|
14
|
-
header: def.id ? titleCase(def.id) : void 0,
|
|
15
|
-
cell: ({ row }) => row.original[def.id]
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
export const defineRowActions = (row, action) => {
|
|
19
|
-
return {
|
|
20
|
-
...action,
|
|
21
|
-
onSelect: () => action.onSelect(row)
|
|
22
|
-
};
|
|
23
|
-
};
|