@movk/nuxt 0.1.1 → 1.1.0
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 +84 -9
- package/dist/module.d.mts +19 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +77 -8
- package/dist/runtime/components/AutoForm.d.vue.ts +12 -6
- package/dist/runtime/components/AutoForm.vue +4 -1
- package/dist/runtime/components/AutoForm.vue.d.ts +12 -6
- package/dist/runtime/components/ColorChooser.d.vue.ts +11 -5
- package/dist/runtime/components/ColorChooser.vue.d.ts +11 -5
- package/dist/runtime/components/DatePicker.d.vue.ts +14 -5
- package/dist/runtime/components/DatePicker.vue.d.ts +14 -5
- package/dist/runtime/components/SlideVerify.d.vue.ts +107 -0
- package/dist/runtime/components/SlideVerify.vue +147 -0
- package/dist/runtime/components/SlideVerify.vue.d.ts +107 -0
- package/dist/runtime/components/StarRating.d.vue.ts +7 -7
- package/dist/runtime/components/StarRating.vue +1 -0
- package/dist/runtime/components/StarRating.vue.d.ts +7 -7
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererArray.d.vue.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererArray.vue +1 -1
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererArray.vue.d.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererField.d.vue.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererField.vue.d.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererLayout.d.vue.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererLayout.vue.d.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererNested.d.vue.ts +6 -4
- package/dist/runtime/components/auto-form-renderer/AutoFormRendererNested.vue.d.ts +6 -4
- package/dist/runtime/components/input/WithCharacterLimit.d.vue.ts +11 -5
- package/dist/runtime/components/input/WithCharacterLimit.vue.d.ts +11 -5
- package/dist/runtime/components/input/WithClear.d.vue.ts +12 -5
- package/dist/runtime/components/input/WithClear.vue.d.ts +12 -5
- package/dist/runtime/components/input/WithCopy.d.vue.ts +12 -5
- package/dist/runtime/components/input/WithCopy.vue.d.ts +12 -5
- package/dist/runtime/components/input/WithPasswordToggle.d.vue.ts +11 -5
- package/dist/runtime/components/input/WithPasswordToggle.vue.d.ts +11 -5
- package/dist/runtime/components/theme-picker/ThemePicker.d.vue.ts +3 -0
- package/dist/runtime/components/theme-picker/ThemePicker.vue +235 -0
- package/dist/runtime/components/theme-picker/ThemePicker.vue.d.ts +3 -0
- package/dist/runtime/components/theme-picker/ThemePickerButton.d.vue.ts +18 -0
- package/dist/runtime/components/theme-picker/ThemePickerButton.vue +34 -0
- package/dist/runtime/components/theme-picker/ThemePickerButton.vue.d.ts +18 -0
- package/dist/runtime/composables/useApiAuth.d.ts +47 -0
- package/dist/runtime/composables/useApiAuth.js +66 -0
- package/dist/runtime/composables/useApiFetch.d.ts +42 -0
- package/dist/runtime/composables/useApiFetch.js +41 -0
- package/dist/runtime/composables/useAutoForm.d.ts +81 -605
- package/dist/runtime/composables/useAutoForm.js +3 -1
- package/dist/runtime/composables/useClientApiFetch.d.ts +24 -0
- package/dist/runtime/composables/useClientApiFetch.js +8 -0
- package/dist/runtime/composables/useDateFormatter.d.ts +21 -7
- package/dist/runtime/composables/useDateFormatter.js +92 -57
- package/dist/runtime/composables/useDownloadWithProgress.d.ts +48 -0
- package/dist/runtime/composables/useDownloadWithProgress.js +85 -0
- package/dist/runtime/composables/useTheme.d.ts +21 -0
- package/dist/runtime/composables/useTheme.js +143 -0
- package/dist/runtime/composables/useUploadWithProgress.d.ts +52 -0
- package/dist/runtime/composables/useUploadWithProgress.js +117 -0
- package/dist/runtime/internal/useAutoFormProvider.js +2 -2
- package/dist/runtime/plugins/api.factory.d.ts +2 -0
- package/dist/runtime/plugins/api.factory.js +186 -0
- package/dist/runtime/plugins/theme.d.ts +2 -0
- package/dist/runtime/plugins/theme.js +89 -0
- package/dist/runtime/schemas/api.d.ts +590 -0
- package/dist/runtime/schemas/api.js +228 -0
- package/dist/runtime/server/api/_movk/session.post.d.ts +10 -0
- package/dist/runtime/server/api/_movk/session.post.js +18 -0
- package/dist/runtime/style.css +1 -0
- package/dist/runtime/types/api.d.ts +218 -0
- package/dist/runtime/types/api.js +0 -0
- package/dist/runtime/types/auth.d.ts +34 -0
- package/dist/runtime/types/auto-form-renderer.d.ts +14 -22
- package/dist/runtime/types/auto-form-renderer.js +0 -0
- package/dist/runtime/types/components.d.ts +29 -41
- package/dist/runtime/types/components.js +0 -0
- package/dist/runtime/types/index.d.ts +1 -0
- package/dist/runtime/types/index.js +3 -2
- package/dist/runtime/utils/api-utils.d.ts +79 -0
- package/dist/runtime/utils/api-utils.js +127 -0
- package/package.json +38 -31
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { InputProps, InputValue } from '@nuxt/ui';
|
|
2
2
|
import type { WithCopyProps } from '../../types/components.js';
|
|
3
|
-
declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>,
|
|
4
|
-
props: __VLS_PrettifyLocal<(WithCopyProps<import("@nuxt/ui/.").AcceptableValue> & {
|
|
3
|
+
declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
4
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<(WithCopyProps<import("@nuxt/ui/.").AcceptableValue> & {
|
|
5
5
|
modelValue?: InputProps["modelValue"];
|
|
6
|
-
}) &
|
|
6
|
+
}) & {
|
|
7
|
+
onBlur?: ((event: FocusEvent) => any) | undefined;
|
|
8
|
+
onChange?: ((event: Event) => any) | undefined;
|
|
9
|
+
onCopy?: ((value: string) => any) | undefined;
|
|
10
|
+
"onUpdate:modelValue"?: ((value: import("@nuxt/ui/.").AcceptableValue | undefined) => any) | undefined;
|
|
11
|
+
}> & (typeof globalThis extends {
|
|
7
12
|
__VLS_PROPS_FALLBACK: infer P;
|
|
8
13
|
} ? P : {});
|
|
9
14
|
expose: (exposed: {}) => void;
|
|
@@ -15,6 +20,8 @@ declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awai
|
|
|
15
20
|
};
|
|
16
21
|
declare const _default: typeof __VLS_export;
|
|
17
22
|
export default _default;
|
|
18
|
-
type __VLS_PrettifyLocal<T> = {
|
|
23
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
24
|
+
[K in keyof T]: T[K];
|
|
25
|
+
} : {
|
|
19
26
|
[K in keyof T as K]: T[K];
|
|
20
|
-
} & {};
|
|
27
|
+
}) & {};
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { InputProps, InputValue } from '@nuxt/ui';
|
|
2
2
|
import type { WithCopyProps } from '../../types/components.js';
|
|
3
|
-
declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>,
|
|
4
|
-
props: __VLS_PrettifyLocal<(WithCopyProps<import("@nuxt/ui/.").AcceptableValue> & {
|
|
3
|
+
declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
4
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<(WithCopyProps<import("@nuxt/ui/.").AcceptableValue> & {
|
|
5
5
|
modelValue?: InputProps["modelValue"];
|
|
6
|
-
}) &
|
|
6
|
+
}) & {
|
|
7
|
+
onBlur?: ((event: FocusEvent) => any) | undefined;
|
|
8
|
+
onChange?: ((event: Event) => any) | undefined;
|
|
9
|
+
onCopy?: ((value: string) => any) | undefined;
|
|
10
|
+
"onUpdate:modelValue"?: ((value: import("@nuxt/ui/.").AcceptableValue | undefined) => any) | undefined;
|
|
11
|
+
}> & (typeof globalThis extends {
|
|
7
12
|
__VLS_PROPS_FALLBACK: infer P;
|
|
8
13
|
} ? P : {});
|
|
9
14
|
expose: (exposed: {}) => void;
|
|
@@ -15,6 +20,8 @@ declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awai
|
|
|
15
20
|
};
|
|
16
21
|
declare const _default: typeof __VLS_export;
|
|
17
22
|
export default _default;
|
|
18
|
-
type __VLS_PrettifyLocal<T> = {
|
|
23
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
24
|
+
[K in keyof T]: T[K];
|
|
25
|
+
} : {
|
|
19
26
|
[K in keyof T as K]: T[K];
|
|
20
|
-
} & {};
|
|
27
|
+
}) & {};
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import type { InputProps, InputValue } from '@nuxt/ui';
|
|
2
2
|
import type { WithPasswordToggleProps } from '../../types/components.js';
|
|
3
|
-
declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>,
|
|
4
|
-
props: __VLS_PrettifyLocal<(WithPasswordToggleProps<import("@nuxt/ui/.").AcceptableValue> & {
|
|
3
|
+
declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
4
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<(WithPasswordToggleProps<import("@nuxt/ui/.").AcceptableValue> & {
|
|
5
5
|
modelValue?: InputProps["modelValue"];
|
|
6
|
-
}) &
|
|
6
|
+
}) & {
|
|
7
|
+
onBlur?: ((event: FocusEvent) => any) | undefined;
|
|
8
|
+
onChange?: ((event: Event) => any) | undefined;
|
|
9
|
+
"onUpdate:modelValue"?: ((value: import("@nuxt/ui/.").AcceptableValue | undefined) => any) | undefined;
|
|
10
|
+
}> & (typeof globalThis extends {
|
|
7
11
|
__VLS_PROPS_FALLBACK: infer P;
|
|
8
12
|
} ? P : {});
|
|
9
13
|
expose: (exposed: {}) => void;
|
|
@@ -15,6 +19,8 @@ declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awai
|
|
|
15
19
|
};
|
|
16
20
|
declare const _default: typeof __VLS_export;
|
|
17
21
|
export default _default;
|
|
18
|
-
type __VLS_PrettifyLocal<T> = {
|
|
22
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
23
|
+
[K in keyof T]: T[K];
|
|
24
|
+
} : {
|
|
19
25
|
[K in keyof T as K]: T[K];
|
|
20
|
-
} & {};
|
|
26
|
+
}) & {};
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import type { InputProps, InputValue } from '@nuxt/ui';
|
|
2
2
|
import type { WithPasswordToggleProps } from '../../types/components.js';
|
|
3
|
-
declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>,
|
|
4
|
-
props: __VLS_PrettifyLocal<(WithPasswordToggleProps<import("@nuxt/ui/.").AcceptableValue> & {
|
|
3
|
+
declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
4
|
+
props: import("vue").PublicProps & __VLS_PrettifyLocal<(WithPasswordToggleProps<import("@nuxt/ui/.").AcceptableValue> & {
|
|
5
5
|
modelValue?: InputProps["modelValue"];
|
|
6
|
-
}) &
|
|
6
|
+
}) & {
|
|
7
|
+
onBlur?: ((event: FocusEvent) => any) | undefined;
|
|
8
|
+
onChange?: ((event: Event) => any) | undefined;
|
|
9
|
+
"onUpdate:modelValue"?: ((value: import("@nuxt/ui/.").AcceptableValue | undefined) => any) | undefined;
|
|
10
|
+
}> & (typeof globalThis extends {
|
|
7
11
|
__VLS_PROPS_FALLBACK: infer P;
|
|
8
12
|
} ? P : {});
|
|
9
13
|
expose: (exposed: {}) => void;
|
|
@@ -15,6 +19,8 @@ declare const __VLS_export: <T extends InputValue>(__VLS_props: NonNullable<Awai
|
|
|
15
19
|
};
|
|
16
20
|
declare const _default: typeof __VLS_export;
|
|
17
21
|
export default _default;
|
|
18
|
-
type __VLS_PrettifyLocal<T> = {
|
|
22
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? {
|
|
23
|
+
[K in keyof T]: T[K];
|
|
24
|
+
} : {
|
|
19
25
|
[K in keyof T as K]: T[K];
|
|
20
|
-
} & {};
|
|
26
|
+
}) & {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useAppConfig, useColorMode } from "#imports";
|
|
3
|
+
import { useClipboard } from "@vueuse/core";
|
|
4
|
+
import { ref } from "vue";
|
|
5
|
+
import { useTheme } from "../../composables/useTheme";
|
|
6
|
+
import ThemePickerButton from "./ThemePickerButton.vue";
|
|
7
|
+
const appConfig = useAppConfig();
|
|
8
|
+
const colorMode = useColorMode();
|
|
9
|
+
const open = ref(false);
|
|
10
|
+
const { copy: copyCSS, copied: copiedCSS } = useClipboard();
|
|
11
|
+
const { copy: copyAppConfig, copied: copiedAppConfig } = useClipboard();
|
|
12
|
+
const {
|
|
13
|
+
neutralColors,
|
|
14
|
+
neutral,
|
|
15
|
+
primaryColors,
|
|
16
|
+
primary,
|
|
17
|
+
setBlackAsPrimary,
|
|
18
|
+
radiuses,
|
|
19
|
+
radius,
|
|
20
|
+
fonts,
|
|
21
|
+
font,
|
|
22
|
+
modes,
|
|
23
|
+
mode,
|
|
24
|
+
hasCSSChanges,
|
|
25
|
+
hasAppConfigChanges,
|
|
26
|
+
exportCSS,
|
|
27
|
+
exportAppConfig,
|
|
28
|
+
resetTheme
|
|
29
|
+
} = useTheme();
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<UPopover
|
|
34
|
+
v-model:open="open"
|
|
35
|
+
:ui="{ content: 'w-72 px-6 py-4 flex flex-col gap-4 overflow-y-auto max-h-[calc(100vh-5rem)]' }"
|
|
36
|
+
>
|
|
37
|
+
<template #default>
|
|
38
|
+
<UButton
|
|
39
|
+
icon="i-lucide-swatch-book"
|
|
40
|
+
color="neutral"
|
|
41
|
+
:variant="open ? 'soft' : 'ghost'"
|
|
42
|
+
square
|
|
43
|
+
aria-label="Color picker"
|
|
44
|
+
:ui="{ leadingIcon: 'text-primary' }"
|
|
45
|
+
/>
|
|
46
|
+
</template>
|
|
47
|
+
|
|
48
|
+
<template #content>
|
|
49
|
+
<fieldset>
|
|
50
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none flex items-center gap-1">
|
|
51
|
+
Primary
|
|
52
|
+
|
|
53
|
+
<UButton
|
|
54
|
+
to="https://ui.nuxt.com/docs/getting-started/theme/css-variables#colors"
|
|
55
|
+
size="xs"
|
|
56
|
+
color="neutral"
|
|
57
|
+
variant="link"
|
|
58
|
+
target="_blank"
|
|
59
|
+
icon="i-lucide-circle-help"
|
|
60
|
+
class="p-0 -my-0.5"
|
|
61
|
+
:ui="{ leadingIcon: 'size-3' }"
|
|
62
|
+
/>
|
|
63
|
+
</legend>
|
|
64
|
+
|
|
65
|
+
<div class="grid grid-cols-3 gap-1 -mx-2">
|
|
66
|
+
<ThemePickerButton label="Black" :selected="appConfig.theme.blackAsPrimary" @click="setBlackAsPrimary(true)">
|
|
67
|
+
<template #leading>
|
|
68
|
+
<span class="inline-block w-2 h-2 rounded-full bg-black dark:bg-white" />
|
|
69
|
+
</template>
|
|
70
|
+
</ThemePickerButton>
|
|
71
|
+
|
|
72
|
+
<ThemePickerButton
|
|
73
|
+
v-for="color in primaryColors"
|
|
74
|
+
:key="color"
|
|
75
|
+
:label="color"
|
|
76
|
+
:chip="color"
|
|
77
|
+
:selected="!appConfig.theme.blackAsPrimary && primary === color"
|
|
78
|
+
@click="primary = color"
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
</fieldset>
|
|
82
|
+
|
|
83
|
+
<fieldset>
|
|
84
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none flex items-center gap-1">
|
|
85
|
+
Neutral
|
|
86
|
+
|
|
87
|
+
<UButton
|
|
88
|
+
to="https://ui.nuxt.com/docs/getting-started/theme/css-variables#text"
|
|
89
|
+
size="xs"
|
|
90
|
+
color="neutral"
|
|
91
|
+
variant="link"
|
|
92
|
+
target="_blank"
|
|
93
|
+
icon="i-lucide-circle-help"
|
|
94
|
+
class="p-0 -my-0.5"
|
|
95
|
+
:ui="{ leadingIcon: 'size-3' }"
|
|
96
|
+
/>
|
|
97
|
+
</legend>
|
|
98
|
+
|
|
99
|
+
<div class="grid grid-cols-3 gap-1 -mx-2">
|
|
100
|
+
<ThemePickerButton
|
|
101
|
+
v-for="color in neutralColors"
|
|
102
|
+
:key="color"
|
|
103
|
+
:label="color"
|
|
104
|
+
:chip="color === 'neutral' ? 'old-neutral' : color"
|
|
105
|
+
:selected="neutral === color"
|
|
106
|
+
@click="neutral = color"
|
|
107
|
+
/>
|
|
108
|
+
</div>
|
|
109
|
+
</fieldset>
|
|
110
|
+
|
|
111
|
+
<fieldset>
|
|
112
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none flex items-center gap-1">
|
|
113
|
+
Radius
|
|
114
|
+
|
|
115
|
+
<UButton
|
|
116
|
+
to="https://ui.nuxt.com/docs/getting-started/theme/css-variables#radius"
|
|
117
|
+
size="xs"
|
|
118
|
+
color="neutral"
|
|
119
|
+
variant="link"
|
|
120
|
+
target="_blank"
|
|
121
|
+
icon="i-lucide-circle-help"
|
|
122
|
+
class="p-0 -my-0.5"
|
|
123
|
+
:ui="{ leadingIcon: 'size-3' }"
|
|
124
|
+
/>
|
|
125
|
+
</legend>
|
|
126
|
+
|
|
127
|
+
<div class="grid grid-cols-5 gap-1 -mx-2">
|
|
128
|
+
<ThemePickerButton
|
|
129
|
+
v-for="r in radiuses"
|
|
130
|
+
:key="r"
|
|
131
|
+
:label="String(r)"
|
|
132
|
+
class="justify-center px-0"
|
|
133
|
+
:selected="radius === r"
|
|
134
|
+
@click="radius = r"
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
</fieldset>
|
|
138
|
+
|
|
139
|
+
<fieldset>
|
|
140
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none flex items-center gap-1">
|
|
141
|
+
Font
|
|
142
|
+
|
|
143
|
+
<UButton
|
|
144
|
+
to="https://ui.nuxt.com/docs/getting-started/integrations/fonts"
|
|
145
|
+
size="xs"
|
|
146
|
+
color="neutral"
|
|
147
|
+
variant="link"
|
|
148
|
+
target="_blank"
|
|
149
|
+
icon="i-lucide-circle-help"
|
|
150
|
+
class="p-0 -my-0.5"
|
|
151
|
+
:ui="{ leadingIcon: 'size-3' }"
|
|
152
|
+
/>
|
|
153
|
+
</legend>
|
|
154
|
+
|
|
155
|
+
<div class="-mx-2">
|
|
156
|
+
<USelect
|
|
157
|
+
v-model="font"
|
|
158
|
+
size="sm"
|
|
159
|
+
color="neutral"
|
|
160
|
+
icon="i-lucide-type"
|
|
161
|
+
:items="fonts"
|
|
162
|
+
class="w-full ring-default rounded-sm hover:bg-elevated/50 text-[11px] data-[state=open]:bg-elevated/50"
|
|
163
|
+
:ui="{ trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200' }"
|
|
164
|
+
/>
|
|
165
|
+
</div>
|
|
166
|
+
</fieldset>
|
|
167
|
+
|
|
168
|
+
<fieldset>
|
|
169
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none flex items-center gap-1">
|
|
170
|
+
Color Mode
|
|
171
|
+
|
|
172
|
+
<UButton
|
|
173
|
+
to="https://ui.nuxt.com/docs/getting-started/integrations/color-mode"
|
|
174
|
+
size="xs"
|
|
175
|
+
color="neutral"
|
|
176
|
+
variant="link"
|
|
177
|
+
target="_blank"
|
|
178
|
+
icon="i-lucide-circle-help"
|
|
179
|
+
class="p-0 -my-0.5"
|
|
180
|
+
:ui="{ leadingIcon: 'size-3' }"
|
|
181
|
+
/>
|
|
182
|
+
</legend>
|
|
183
|
+
|
|
184
|
+
<div class="grid grid-cols-3 gap-1 -mx-2">
|
|
185
|
+
<ThemePickerButton
|
|
186
|
+
v-for="m in modes"
|
|
187
|
+
:key="m.label"
|
|
188
|
+
v-bind="m"
|
|
189
|
+
:selected="colorMode.preference === m.label"
|
|
190
|
+
@click="mode = m.label"
|
|
191
|
+
/>
|
|
192
|
+
</div>
|
|
193
|
+
</fieldset>
|
|
194
|
+
|
|
195
|
+
<fieldset v-if="hasCSSChanges || hasAppConfigChanges">
|
|
196
|
+
<legend class="text-[11px] leading-none font-semibold mb-2 select-none">
|
|
197
|
+
Export
|
|
198
|
+
</legend>
|
|
199
|
+
|
|
200
|
+
<div class="flex items-center justify-between gap-1 -mx-2">
|
|
201
|
+
<UButton
|
|
202
|
+
v-if="hasCSSChanges"
|
|
203
|
+
color="neutral"
|
|
204
|
+
variant="soft"
|
|
205
|
+
size="sm"
|
|
206
|
+
label="main.css"
|
|
207
|
+
class="flex-1 text-[11px]"
|
|
208
|
+
:icon="copiedCSS ? appConfig.ui.icons.copyCheck : appConfig.ui.icons.copy"
|
|
209
|
+
@click="copyCSS(exportCSS())"
|
|
210
|
+
/>
|
|
211
|
+
<UButton
|
|
212
|
+
v-if="hasAppConfigChanges"
|
|
213
|
+
color="neutral"
|
|
214
|
+
variant="soft"
|
|
215
|
+
size="sm"
|
|
216
|
+
label="app.config.ts"
|
|
217
|
+
:icon="copiedAppConfig ? appConfig.ui.icons.copyCheck : appConfig.ui.icons.copy"
|
|
218
|
+
class="flex-1 text-[11px]"
|
|
219
|
+
@click="copyAppConfig(exportAppConfig())"
|
|
220
|
+
/>
|
|
221
|
+
<UTooltip text="Reset theme">
|
|
222
|
+
<UButton
|
|
223
|
+
color="neutral"
|
|
224
|
+
variant="outline"
|
|
225
|
+
size="sm"
|
|
226
|
+
icon="i-lucide-rotate-ccw"
|
|
227
|
+
class="ms-auto ring-default hover:bg-elevated/50"
|
|
228
|
+
@click="resetTheme"
|
|
229
|
+
/>
|
|
230
|
+
</UTooltip>
|
|
231
|
+
</div>
|
|
232
|
+
</fieldset>
|
|
233
|
+
</template>
|
|
234
|
+
</UPopover>
|
|
235
|
+
</template>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
label: string;
|
|
3
|
+
icon?: string;
|
|
4
|
+
chip?: string;
|
|
5
|
+
selected?: boolean;
|
|
6
|
+
};
|
|
7
|
+
type __VLS_Slots = {
|
|
8
|
+
leading: () => any;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
14
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
15
|
+
new (): {
|
|
16
|
+
$slots: S;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
defineProps({
|
|
3
|
+
label: { type: String, required: true },
|
|
4
|
+
icon: { type: String, required: false },
|
|
5
|
+
chip: { type: String, required: false },
|
|
6
|
+
selected: { type: Boolean, required: false }
|
|
7
|
+
});
|
|
8
|
+
const slots = defineSlots();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<UButton
|
|
13
|
+
size="sm"
|
|
14
|
+
color="neutral"
|
|
15
|
+
variant="outline"
|
|
16
|
+
:icon="icon"
|
|
17
|
+
:label="label"
|
|
18
|
+
class="capitalize ring-default rounded-sm text-[11px]"
|
|
19
|
+
:class="selected ? 'bg-elevated' : 'hover:bg-elevated/50'"
|
|
20
|
+
>
|
|
21
|
+
<template v-if="chip || !!slots.leading" #leading>
|
|
22
|
+
<slot name="leading">
|
|
23
|
+
<span
|
|
24
|
+
class="inline-block size-2 rounded-full bg-(--color-light) dark:bg-(--color-dark)"
|
|
25
|
+
|
|
26
|
+
:style="{
|
|
27
|
+
'--color-light': `var(--color-${chip}-500)`,
|
|
28
|
+
'--color-dark': `var(--color-${chip}-400)`
|
|
29
|
+
}"
|
|
30
|
+
/>
|
|
31
|
+
</slot>
|
|
32
|
+
</template>
|
|
33
|
+
</UButton>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
label: string;
|
|
3
|
+
icon?: string;
|
|
4
|
+
chip?: string;
|
|
5
|
+
selected?: boolean;
|
|
6
|
+
};
|
|
7
|
+
type __VLS_Slots = {
|
|
8
|
+
leading: () => any;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
14
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
15
|
+
new (): {
|
|
16
|
+
$slots: S;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { UseApiAuthReturn } from '../types/api.js';
|
|
2
|
+
/**
|
|
3
|
+
* API 认证 Composable
|
|
4
|
+
*
|
|
5
|
+
* 提供完整的登录、登出、刷新用户信息等功能,
|
|
6
|
+
* 与 nuxt-auth-utils 无缝集成。
|
|
7
|
+
*
|
|
8
|
+
* @returns UseApiAuthReturn 认证相关方法和状态
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const { login, clear, loggedIn, user } = useApiAuth()
|
|
13
|
+
*
|
|
14
|
+
* // 基础登录
|
|
15
|
+
* await login({
|
|
16
|
+
* loginPath: '/auth/login',
|
|
17
|
+
* credentials: { username: 'admin', password: '123456' }
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* // 登录后获取用户信息
|
|
21
|
+
* await login({
|
|
22
|
+
* loginPath: '/auth/login',
|
|
23
|
+
* credentials: { username: 'admin', password: '123456' },
|
|
24
|
+
* userInfoPath: '/auth/me'
|
|
25
|
+
* })
|
|
26
|
+
*
|
|
27
|
+
* // 自定义 token 提取和 session 构建
|
|
28
|
+
* await login({
|
|
29
|
+
* loginPath: '/auth/login',
|
|
30
|
+
* credentials: { username: 'admin', password: '123456' },
|
|
31
|
+
* tokenExtractor: (res) => res.data?.accessToken,
|
|
32
|
+
* sessionBuilder: (user, token) => ({
|
|
33
|
+
* user: { id: user.id, name: user.name },
|
|
34
|
+
* secure: { token, permissions: user.permissions }
|
|
35
|
+
* })
|
|
36
|
+
* })
|
|
37
|
+
*
|
|
38
|
+
* // 登出
|
|
39
|
+
* await clear()
|
|
40
|
+
*
|
|
41
|
+
* // 响应式状态
|
|
42
|
+
* if (loggedIn.value) {
|
|
43
|
+
* console.log('当前用户:', user.value)
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function useApiAuth(): UseApiAuthReturn;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { getPath } from "@movk/core";
|
|
2
|
+
import { useNuxtApp, useRuntimeConfig, useUserSession } from "#imports";
|
|
3
|
+
export function useApiAuth() {
|
|
4
|
+
const { $api } = useNuxtApp();
|
|
5
|
+
const userSession = useUserSession();
|
|
6
|
+
const moduleConfig = useRuntimeConfig().public.movkApi;
|
|
7
|
+
const buildAuthHeader = (token, authConfig = {}) => {
|
|
8
|
+
const tokenType = authConfig.tokenType === "Custom" ? authConfig.customTokenType || "" : authConfig.tokenType || "Bearer";
|
|
9
|
+
return tokenType ? `${tokenType} ${token}` : token;
|
|
10
|
+
};
|
|
11
|
+
const getHeaderName = (authConfig = {}) => {
|
|
12
|
+
return authConfig.headerName || "Authorization";
|
|
13
|
+
};
|
|
14
|
+
const defaultTokenExtractor = (response) => {
|
|
15
|
+
return getPath(response, "data.token") ?? getPath(response, "data.accessToken") ?? getPath(response, "token");
|
|
16
|
+
};
|
|
17
|
+
const defaultSessionBuilder = (user, token) => ({
|
|
18
|
+
user,
|
|
19
|
+
token,
|
|
20
|
+
loggedInAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
21
|
+
});
|
|
22
|
+
async function login(options) {
|
|
23
|
+
const {
|
|
24
|
+
loginPath,
|
|
25
|
+
credentials,
|
|
26
|
+
userInfoPath,
|
|
27
|
+
tokenExtractor = defaultTokenExtractor,
|
|
28
|
+
sessionBuilder = defaultSessionBuilder,
|
|
29
|
+
endpoint
|
|
30
|
+
} = options;
|
|
31
|
+
const api = endpoint ? $api.use(endpoint) : $api;
|
|
32
|
+
const loginResponse = await api.$fetch(loginPath, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
body: credentials
|
|
35
|
+
});
|
|
36
|
+
const token = tokenExtractor(loginResponse);
|
|
37
|
+
if (!token) {
|
|
38
|
+
throw new Error("Login failed: token not found in response");
|
|
39
|
+
}
|
|
40
|
+
let userInfo;
|
|
41
|
+
if (userInfoPath) {
|
|
42
|
+
const endpointConfig = api.getConfig();
|
|
43
|
+
const authConfig = endpointConfig.auth || moduleConfig.auth || {};
|
|
44
|
+
const headerName = getHeaderName(authConfig);
|
|
45
|
+
const headerValue = buildAuthHeader(token, authConfig);
|
|
46
|
+
const userResponse = await api.$fetch(userInfoPath, {
|
|
47
|
+
headers: { [headerName]: headerValue },
|
|
48
|
+
context: { toast: false }
|
|
49
|
+
});
|
|
50
|
+
userInfo = getPath(userResponse, "data") ?? userResponse;
|
|
51
|
+
} else {
|
|
52
|
+
userInfo = getPath(loginResponse, "data") ?? loginResponse;
|
|
53
|
+
}
|
|
54
|
+
const sessionData = sessionBuilder(userInfo, token);
|
|
55
|
+
await $fetch("/api/_movk/session", {
|
|
56
|
+
method: "POST",
|
|
57
|
+
body: sessionData
|
|
58
|
+
});
|
|
59
|
+
await userSession.fetch();
|
|
60
|
+
return { user: userInfo, token };
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
login,
|
|
64
|
+
...userSession
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { UseApiFetchOptions, UseApiFetchReturn } from '../types/api.js';
|
|
2
|
+
/**
|
|
3
|
+
* API Fetch 组合式函数
|
|
4
|
+
*
|
|
5
|
+
* 基于 Nuxt useFetch 封装,提供:
|
|
6
|
+
* - 自动认证(从 session 获取 token)
|
|
7
|
+
* - 业务状态码检查
|
|
8
|
+
* - Toast 提示(通过内置 hooks 统一处理)
|
|
9
|
+
* - 自动数据解包
|
|
10
|
+
* - 支持用户自定义 hooks(与内置 hooks 合并执行)
|
|
11
|
+
*
|
|
12
|
+
* @typeParam ResT - API 响应 data 字段的原始类型
|
|
13
|
+
* @typeParam DataT - transform 转换后的最终类型(默认等于 ResT)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* // 基础用法(自动解包 data 字段)
|
|
18
|
+
* const { data, pending, error } = await useApiFetch<User[]>('/users')
|
|
19
|
+
*
|
|
20
|
+
* // POST 请求
|
|
21
|
+
* const { data } = await useApiFetch('/users', {
|
|
22
|
+
* method: 'POST',
|
|
23
|
+
* body: { name: 'test' }
|
|
24
|
+
* })
|
|
25
|
+
*
|
|
26
|
+
* // 自定义 transform(双泛型,接收解包后的数据)
|
|
27
|
+
* const { data } = await useApiFetch<{ content: User[] }, User[]>('/users', {
|
|
28
|
+
* transform: ({ content }) => content ?? []
|
|
29
|
+
* })
|
|
30
|
+
*
|
|
31
|
+
* // 使用其他端点
|
|
32
|
+
* const { data } = await useApiFetch('/users', { endpoint: 'v2' })
|
|
33
|
+
*
|
|
34
|
+
* // 自定义 hooks(与内置 hooks 合并执行)
|
|
35
|
+
* const { data } = await useApiFetch('/users', {
|
|
36
|
+
* onResponse({ response }) {
|
|
37
|
+
* console.log('用户自定义处理:', response._data)
|
|
38
|
+
* }
|
|
39
|
+
* })
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function useApiFetch<ResT = unknown, DataT = ResT>(url: string | (() => string), options?: UseApiFetchOptions<ResT, DataT>): UseApiFetchReturn<DataT>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useNuxtApp, useFetch } from "#imports";
|
|
2
|
+
import { createTransform, mergeFetchHooks } from "../utils/api-utils.js";
|
|
3
|
+
export function useApiFetch(url, options = {}) {
|
|
4
|
+
const { $api } = useNuxtApp();
|
|
5
|
+
const {
|
|
6
|
+
endpoint,
|
|
7
|
+
toast,
|
|
8
|
+
skipBusinessCheck = false,
|
|
9
|
+
transform: userTransform,
|
|
10
|
+
onRequest: userOnRequest,
|
|
11
|
+
onRequestError: userOnRequestError,
|
|
12
|
+
onResponse: userOnResponse,
|
|
13
|
+
onResponseError: userOnResponseError,
|
|
14
|
+
...fetchOptions
|
|
15
|
+
} = options;
|
|
16
|
+
const apiInstance = endpoint ? $api.use(endpoint) : $api;
|
|
17
|
+
const endpointConfig = apiInstance.getConfig();
|
|
18
|
+
const builtinHooks = endpointConfig.builtinHooks || {};
|
|
19
|
+
const transformFn = createTransform({
|
|
20
|
+
skipBusinessCheck,
|
|
21
|
+
userTransform,
|
|
22
|
+
successConfig: endpointConfig.response
|
|
23
|
+
});
|
|
24
|
+
const mergedHooks = mergeFetchHooks(builtinHooks, {
|
|
25
|
+
onRequest: userOnRequest,
|
|
26
|
+
onRequestError: userOnRequestError,
|
|
27
|
+
onResponse: userOnResponse,
|
|
28
|
+
onResponseError: userOnResponseError
|
|
29
|
+
});
|
|
30
|
+
const context = { toast, skipBusinessCheck };
|
|
31
|
+
return useFetch(url, {
|
|
32
|
+
...fetchOptions,
|
|
33
|
+
$fetch: apiInstance.$fetch,
|
|
34
|
+
transform: transformFn,
|
|
35
|
+
onRequest: mergedHooks.onRequest,
|
|
36
|
+
onRequestError: mergedHooks.onRequestError,
|
|
37
|
+
onResponse: mergedHooks.onResponse,
|
|
38
|
+
onResponseError: mergedHooks.onResponseError,
|
|
39
|
+
context
|
|
40
|
+
});
|
|
41
|
+
}
|