@abraca/nuxt 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.d.mts +18 -7
- package/dist/module.json +1 -1
- package/dist/module.mjs +21 -5
- package/dist/runtime/assets/aware-tokens.css +1 -0
- package/dist/runtime/components/AAccountSwitcherModal.d.vue.ts +16 -1
- package/dist/runtime/components/AAccountSwitcherModal.vue +33 -4
- package/dist/runtime/components/AAccountSwitcherModal.vue.d.ts +16 -1
- package/dist/runtime/components/AAuthLinkLanding.d.vue.ts +3 -0
- package/dist/runtime/components/AAuthLinkLanding.vue +85 -0
- package/dist/runtime/components/AAuthLinkLanding.vue.d.ts +3 -0
- package/dist/runtime/components/AClaimAccountModal.d.vue.ts +7 -1
- package/dist/runtime/components/AClaimAccountModal.vue +28 -13
- package/dist/runtime/components/AClaimAccountModal.vue.d.ts +7 -1
- package/dist/runtime/components/AEmailVerifyConfirmModal.d.vue.ts +30 -0
- package/dist/runtime/components/AEmailVerifyConfirmModal.vue +100 -0
- package/dist/runtime/components/AEmailVerifyConfirmModal.vue.d.ts +30 -0
- package/dist/runtime/components/AEmailVerifyRequestCard.d.vue.ts +22 -0
- package/dist/runtime/components/AEmailVerifyRequestCard.vue +65 -0
- package/dist/runtime/components/AEmailVerifyRequestCard.vue.d.ts +22 -0
- package/dist/runtime/components/AMnemonicLoginModal.d.vue.ts +1 -1
- package/dist/runtime/components/AMnemonicLoginModal.vue.d.ts +1 -1
- package/dist/runtime/components/ANodePanel.vue +2 -0
- package/dist/runtime/components/ANotificationBell.d.vue.ts +2 -2
- package/dist/runtime/components/ANotificationBell.vue.d.ts +2 -2
- package/dist/runtime/components/APasswordChangeModal.d.vue.ts +28 -0
- package/dist/runtime/components/APasswordChangeModal.vue +178 -0
- package/dist/runtime/components/APasswordChangeModal.vue.d.ts +28 -0
- package/dist/runtime/components/APasswordLoginModal.d.vue.ts +42 -0
- package/dist/runtime/components/APasswordLoginModal.vue +177 -0
- package/dist/runtime/components/APasswordLoginModal.vue.d.ts +42 -0
- package/dist/runtime/components/APasswordRegisterModal.d.vue.ts +49 -0
- package/dist/runtime/components/APasswordRegisterModal.vue +262 -0
- package/dist/runtime/components/APasswordRegisterModal.vue.d.ts +49 -0
- package/dist/runtime/components/APasswordResetConfirmModal.d.vue.ts +31 -0
- package/dist/runtime/components/APasswordResetConfirmModal.vue +154 -0
- package/dist/runtime/components/APasswordResetConfirmModal.vue.d.ts +31 -0
- package/dist/runtime/components/APasswordResetRequestModal.d.vue.ts +35 -0
- package/dist/runtime/components/APasswordResetRequestModal.vue +113 -0
- package/dist/runtime/components/APasswordResetRequestModal.vue.d.ts +35 -0
- package/dist/runtime/components/ASetPasswordCard.d.vue.ts +26 -0
- package/dist/runtime/components/ASetPasswordCard.vue +139 -0
- package/dist/runtime/components/ASetPasswordCard.vue.d.ts +26 -0
- package/dist/runtime/components/aware/AAccordion.d.vue.ts +2 -0
- package/dist/runtime/components/aware/AAccordion.vue +11 -1
- package/dist/runtime/components/aware/AAccordion.vue.d.ts +2 -0
- package/dist/runtime/components/aware/AButton.vue +3 -3
- package/dist/runtime/components/aware/ACollapsible.d.vue.ts +2 -0
- package/dist/runtime/components/aware/ACollapsible.vue +9 -1
- package/dist/runtime/components/aware/ACollapsible.vue.d.ts +2 -0
- package/dist/runtime/components/aware/AGlobalFocusLayer.vue +1 -1
- package/dist/runtime/components/aware/AHoverItem.vue +28 -3
- package/dist/runtime/components/aware/AModal.d.vue.ts +2 -0
- package/dist/runtime/components/aware/AModal.vue +9 -1
- package/dist/runtime/components/aware/AModal.vue.d.ts +2 -0
- package/dist/runtime/components/aware/APresenceBlobs.vue +1 -1
- package/dist/runtime/components/aware/APresenceCursors.vue +1 -1
- package/dist/runtime/components/aware/AScroll.d.vue.ts +2 -0
- package/dist/runtime/components/aware/AScroll.vue +13 -3
- package/dist/runtime/components/aware/AScroll.vue.d.ts +2 -0
- package/dist/runtime/components/aware/ASlideover.d.vue.ts +2 -0
- package/dist/runtime/components/aware/ASlideover.vue +9 -1
- package/dist/runtime/components/aware/ASlideover.vue.d.ts +2 -0
- package/dist/runtime/components/aware/ASlider.vue +1 -0
- package/dist/runtime/components/aware/ATabs.d.vue.ts +2 -0
- package/dist/runtime/components/aware/ATabs.vue +9 -1
- package/dist/runtime/components/aware/ATabs.vue.d.ts +2 -0
- package/dist/runtime/components/chat/ANodeChatPanel.vue +1 -0
- package/dist/runtime/components/editor/AEditorRedoButton.d.vue.ts +2 -2
- package/dist/runtime/components/editor/AEditorRedoButton.vue.d.ts +2 -2
- package/dist/runtime/components/editor/AEditorUndoButton.d.vue.ts +2 -2
- package/dist/runtime/components/editor/AEditorUndoButton.vue.d.ts +2 -2
- package/dist/runtime/components/shell/AUserProfilePopover.d.vue.ts +1 -1
- package/dist/runtime/components/shell/AUserProfilePopover.vue.d.ts +1 -1
- package/dist/runtime/composables/useAAField.js +7 -4
- package/dist/runtime/composables/useAAFocus.js +10 -5
- package/dist/runtime/composables/useAAFollowAnchor.js +68 -34
- package/dist/runtime/composables/useAAFollowPeer.d.ts +7 -4
- package/dist/runtime/composables/useAAFollowPeer.js +60 -11
- package/dist/runtime/composables/useAAViewport.d.ts +1 -1
- package/dist/runtime/composables/useAbracadabraAuth.d.ts +2 -0
- package/dist/runtime/composables/useAbracadabraAuth.js +2 -0
- package/dist/runtime/composables/useEmailVerification.d.ts +40 -26
- package/dist/runtime/composables/useEmailVerification.js +95 -43
- package/dist/runtime/composables/usePasswordAuth.d.ts +64 -0
- package/dist/runtime/composables/usePasswordAuth.js +126 -0
- package/dist/runtime/composables/useTiptapHistory.d.ts +2 -2
- package/dist/runtime/composables/useTiptapHistory.js +5 -5
- package/dist/runtime/extensions/views/MetaFieldView.vue +23 -6
- package/dist/runtime/plugin-abracadabra.client.js +57 -8
- package/dist/runtime/plugin-abracadabra.server.js +2 -0
- package/dist/runtime/server/plugins/abracadabra-service.js +20 -9
- package/dist/runtime/types.d.ts +11 -0
- package/dist/runtime/utils/awareRingStyle.js +1 -1
- package/package.json +7 -7
- package/dist/runtime/components/renderers/ASpatialRenderer.d.vue.ts +0 -19
- package/dist/runtime/components/renderers/ASpatialRenderer.vue +0 -459
- package/dist/runtime/components/renderers/ASpatialRenderer.vue.d.ts +0 -19
- package/dist/runtime/components/renderers/spatial/SpatialGround.d.vue.ts +0 -20
- package/dist/runtime/components/renderers/spatial/SpatialGround.vue +0 -26
- package/dist/runtime/components/renderers/spatial/SpatialGround.vue.d.ts +0 -20
- package/dist/runtime/components/renderers/spatial/SpatialObject.d.vue.ts +0 -17
- package/dist/runtime/components/renderers/spatial/SpatialObject.vue +0 -257
- package/dist/runtime/components/renderers/spatial/SpatialObject.vue.d.ts +0 -17
- package/dist/runtime/components/renderers/spatial/SpatialSceneBridge.d.vue.ts +0 -15
- package/dist/runtime/components/renderers/spatial/SpatialSceneBridge.vue +0 -18
- package/dist/runtime/components/renderers/spatial/SpatialSceneBridge.vue.d.ts +0 -15
- package/dist/runtime/components/renderers/spatial/SpatialTransformInputs.d.vue.ts +0 -16
- package/dist/runtime/components/renderers/spatial/SpatialTransformInputs.vue +0 -66
- package/dist/runtime/components/renderers/spatial/SpatialTransformInputs.vue.d.ts +0 -16
- package/dist/runtime/components/renderers/spatial/SpatialUserAvatar.d.vue.ts +0 -8
- package/dist/runtime/components/renderers/spatial/SpatialUserAvatar.vue +0 -53
- package/dist/runtime/components/renderers/spatial/SpatialUserAvatar.vue.d.ts +0 -8
- package/dist/runtime/composables/useSpatialCamera.d.ts +0 -16
- package/dist/runtime/composables/useSpatialCamera.js +0 -175
- package/dist/runtime/composables/useSpatialDrag.d.ts +0 -14
- package/dist/runtime/composables/useSpatialDrag.js +0 -137
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
open?: boolean;
|
|
3
|
+
loading?: boolean;
|
|
4
|
+
error?: string | null;
|
|
5
|
+
title?: string;
|
|
6
|
+
subtitle?: string;
|
|
7
|
+
/** Server-enforced minimum password length (mirrored client-side). */
|
|
8
|
+
minLength?: number;
|
|
9
|
+
/** Show optional email field. */
|
|
10
|
+
showEmail?: boolean;
|
|
11
|
+
/** Show optional display-name field. */
|
|
12
|
+
showDisplayName?: boolean;
|
|
13
|
+
/** Show optional invite-code field. */
|
|
14
|
+
showInviteCode?: boolean;
|
|
15
|
+
/** Show "Already have an account? Sign in" link. */
|
|
16
|
+
showSignInLink?: boolean;
|
|
17
|
+
};
|
|
18
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
19
|
+
submit: (payload: {
|
|
20
|
+
username: string;
|
|
21
|
+
password: string;
|
|
22
|
+
email?: string;
|
|
23
|
+
displayName?: string;
|
|
24
|
+
inviteCode?: string;
|
|
25
|
+
}) => any;
|
|
26
|
+
"update:open": (v: boolean) => any;
|
|
27
|
+
signin: () => any;
|
|
28
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
29
|
+
onSubmit?: ((payload: {
|
|
30
|
+
username: string;
|
|
31
|
+
password: string;
|
|
32
|
+
email?: string;
|
|
33
|
+
displayName?: string;
|
|
34
|
+
inviteCode?: string;
|
|
35
|
+
}) => any) | undefined;
|
|
36
|
+
"onUpdate:open"?: ((v: boolean) => any) | undefined;
|
|
37
|
+
onSignin?: (() => any) | undefined;
|
|
38
|
+
}>, {
|
|
39
|
+
subtitle: string;
|
|
40
|
+
title: string;
|
|
41
|
+
minLength: number;
|
|
42
|
+
loading: boolean;
|
|
43
|
+
showInviteCode: boolean;
|
|
44
|
+
showEmail: boolean;
|
|
45
|
+
showDisplayName: boolean;
|
|
46
|
+
showSignInLink: boolean;
|
|
47
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
48
|
+
declare const _default: typeof __VLS_export;
|
|
49
|
+
export default _default;
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
open: { type: Boolean, required: false },
|
|
5
|
+
loading: { type: Boolean, required: false, default: false },
|
|
6
|
+
error: { type: [String, null], required: false },
|
|
7
|
+
title: { type: String, required: false, default: "Create your account" },
|
|
8
|
+
subtitle: { type: String, required: false, default: "Pick a username and a password. You can change either later." },
|
|
9
|
+
minLength: { type: Number, required: false, default: 8 },
|
|
10
|
+
showEmail: { type: Boolean, required: false, default: true },
|
|
11
|
+
showDisplayName: { type: Boolean, required: false, default: false },
|
|
12
|
+
showInviteCode: { type: Boolean, required: false, default: true },
|
|
13
|
+
showSignInLink: { type: Boolean, required: false, default: true }
|
|
14
|
+
});
|
|
15
|
+
const emit = defineEmits(["update:open", "submit", "signin"]);
|
|
16
|
+
const open = computed({
|
|
17
|
+
get: () => !!props.open,
|
|
18
|
+
set: (v) => emit("update:open", v)
|
|
19
|
+
});
|
|
20
|
+
const username = ref("");
|
|
21
|
+
const password = ref("");
|
|
22
|
+
const confirm = ref("");
|
|
23
|
+
const email = ref("");
|
|
24
|
+
const displayName = ref("");
|
|
25
|
+
const inviteCode = ref("");
|
|
26
|
+
const showPassword = ref(false);
|
|
27
|
+
watch(() => props.open, (v) => {
|
|
28
|
+
if (!v) return;
|
|
29
|
+
username.value = "";
|
|
30
|
+
password.value = "";
|
|
31
|
+
confirm.value = "";
|
|
32
|
+
email.value = "";
|
|
33
|
+
displayName.value = "";
|
|
34
|
+
inviteCode.value = "";
|
|
35
|
+
showPassword.value = false;
|
|
36
|
+
});
|
|
37
|
+
const passwordTooShort = computed(
|
|
38
|
+
() => password.value.length > 0 && password.value.length < props.minLength
|
|
39
|
+
);
|
|
40
|
+
const confirmMismatch = computed(
|
|
41
|
+
() => confirm.value.length > 0 && confirm.value !== password.value
|
|
42
|
+
);
|
|
43
|
+
const emailLooksValid = computed(
|
|
44
|
+
() => !email.value || /^[^\s@]+@[^\s@]+\.[^\s.@]+$/.test(email.value.trim())
|
|
45
|
+
);
|
|
46
|
+
const strength = computed(() => {
|
|
47
|
+
const p = password.value;
|
|
48
|
+
if (!p) return { score: 0, label: "" };
|
|
49
|
+
let score = 0;
|
|
50
|
+
if (p.length >= props.minLength) score++;
|
|
51
|
+
if (p.length >= props.minLength + 4) score++;
|
|
52
|
+
if (/[A-Z]/.test(p) && /[a-z]/.test(p)) score++;
|
|
53
|
+
if (/\d/.test(p)) score++;
|
|
54
|
+
if (/[^a-z0-9]/i.test(p)) score++;
|
|
55
|
+
const labels = ["Too short", "Weak", "Fair", "Good", "Strong", "Strong"];
|
|
56
|
+
return { score, label: labels[Math.min(score, 5)] };
|
|
57
|
+
});
|
|
58
|
+
const canSubmit = computed(
|
|
59
|
+
() => !!username.value.trim() && password.value.length >= props.minLength && confirm.value === password.value && emailLooksValid.value && !props.loading
|
|
60
|
+
);
|
|
61
|
+
function submit() {
|
|
62
|
+
if (!canSubmit.value) return;
|
|
63
|
+
emit("submit", {
|
|
64
|
+
username: username.value.trim(),
|
|
65
|
+
password: password.value,
|
|
66
|
+
email: email.value.trim() || void 0,
|
|
67
|
+
displayName: displayName.value.trim() || void 0,
|
|
68
|
+
inviteCode: inviteCode.value.trim() || void 0
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<template>
|
|
74
|
+
<UModal
|
|
75
|
+
v-model:open="open"
|
|
76
|
+
:title="title"
|
|
77
|
+
:ui="{ content: 'sm:max-w-md' }"
|
|
78
|
+
>
|
|
79
|
+
<template #body>
|
|
80
|
+
<div class="flex flex-col gap-4">
|
|
81
|
+
<p class="text-sm text-(--ui-text-muted)">
|
|
82
|
+
{{ subtitle }}
|
|
83
|
+
</p>
|
|
84
|
+
|
|
85
|
+
<UAlert
|
|
86
|
+
v-if="error"
|
|
87
|
+
color="error"
|
|
88
|
+
variant="soft"
|
|
89
|
+
icon="i-lucide-triangle-alert"
|
|
90
|
+
:description="error"
|
|
91
|
+
/>
|
|
92
|
+
|
|
93
|
+
<div class="flex flex-col gap-1">
|
|
94
|
+
<label class="text-xs font-medium text-(--ui-text-muted)">Username</label>
|
|
95
|
+
<UInput
|
|
96
|
+
v-model="username"
|
|
97
|
+
size="md"
|
|
98
|
+
autofocus
|
|
99
|
+
autocomplete="username"
|
|
100
|
+
placeholder="your-handle"
|
|
101
|
+
icon="i-lucide-at-sign"
|
|
102
|
+
@keydown.enter="submit"
|
|
103
|
+
/>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div
|
|
107
|
+
v-if="showDisplayName"
|
|
108
|
+
class="flex flex-col gap-1"
|
|
109
|
+
>
|
|
110
|
+
<label class="text-xs font-medium text-(--ui-text-muted)">Display name (optional)</label>
|
|
111
|
+
<UInput
|
|
112
|
+
v-model="displayName"
|
|
113
|
+
size="md"
|
|
114
|
+
autocomplete="name"
|
|
115
|
+
placeholder="Visible to other people"
|
|
116
|
+
icon="i-lucide-user"
|
|
117
|
+
@keydown.enter="submit"
|
|
118
|
+
/>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div
|
|
122
|
+
v-if="showEmail"
|
|
123
|
+
class="flex flex-col gap-1"
|
|
124
|
+
>
|
|
125
|
+
<label class="text-xs font-medium text-(--ui-text-muted)">Email (optional)</label>
|
|
126
|
+
<UInput
|
|
127
|
+
v-model="email"
|
|
128
|
+
type="email"
|
|
129
|
+
size="md"
|
|
130
|
+
autocomplete="email"
|
|
131
|
+
placeholder="you@example.com"
|
|
132
|
+
icon="i-lucide-mail"
|
|
133
|
+
@keydown.enter="submit"
|
|
134
|
+
/>
|
|
135
|
+
<p
|
|
136
|
+
v-if="email && !emailLooksValid"
|
|
137
|
+
class="text-xs text-(--ui-color-error-500)"
|
|
138
|
+
>
|
|
139
|
+
That doesn't look like an email address.
|
|
140
|
+
</p>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<div class="flex flex-col gap-1">
|
|
144
|
+
<label class="text-xs font-medium text-(--ui-text-muted)">Password</label>
|
|
145
|
+
<UInput
|
|
146
|
+
v-model="password"
|
|
147
|
+
:type="showPassword ? 'text' : 'password'"
|
|
148
|
+
size="md"
|
|
149
|
+
autocomplete="new-password"
|
|
150
|
+
:placeholder="`${minLength}+ characters`"
|
|
151
|
+
icon="i-lucide-lock"
|
|
152
|
+
:ui="{ trailing: 'pe-1' }"
|
|
153
|
+
@keydown.enter="submit"
|
|
154
|
+
>
|
|
155
|
+
<template #trailing>
|
|
156
|
+
<UButton
|
|
157
|
+
tabindex="-1"
|
|
158
|
+
variant="ghost"
|
|
159
|
+
color="neutral"
|
|
160
|
+
size="xs"
|
|
161
|
+
:icon="showPassword ? 'i-lucide-eye-off' : 'i-lucide-eye'"
|
|
162
|
+
:aria-label="showPassword ? 'Hide password' : 'Show password'"
|
|
163
|
+
@click="showPassword = !showPassword"
|
|
164
|
+
/>
|
|
165
|
+
</template>
|
|
166
|
+
</UInput>
|
|
167
|
+
<div
|
|
168
|
+
v-if="password.length > 0"
|
|
169
|
+
class="flex items-center gap-1.5 mt-1"
|
|
170
|
+
>
|
|
171
|
+
<div class="flex-1 grid grid-cols-5 gap-0.5 h-1">
|
|
172
|
+
<div
|
|
173
|
+
v-for="i in 5"
|
|
174
|
+
:key="i"
|
|
175
|
+
class="rounded-full transition-colors"
|
|
176
|
+
:class="i <= strength.score ? strength.score >= 4 ? 'bg-(--ui-color-success-500)' : strength.score >= 2 ? 'bg-(--ui-color-warning-500)' : 'bg-(--ui-color-error-500)' : 'bg-(--ui-border)'"
|
|
177
|
+
/>
|
|
178
|
+
</div>
|
|
179
|
+
<span
|
|
180
|
+
class="text-xs font-mono w-12 text-right"
|
|
181
|
+
:class="strength.score >= 4 ? 'text-(--ui-color-success-500)' : strength.score >= 2 ? 'text-(--ui-color-warning-500)' : 'text-(--ui-color-error-500)'"
|
|
182
|
+
>{{ strength.label }}</span>
|
|
183
|
+
</div>
|
|
184
|
+
<p
|
|
185
|
+
v-if="passwordTooShort"
|
|
186
|
+
class="text-xs text-(--ui-color-error-500)"
|
|
187
|
+
>
|
|
188
|
+
At least {{ minLength }} characters.
|
|
189
|
+
</p>
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<div class="flex flex-col gap-1">
|
|
193
|
+
<label class="text-xs font-medium text-(--ui-text-muted)">Confirm password</label>
|
|
194
|
+
<UInput
|
|
195
|
+
v-model="confirm"
|
|
196
|
+
:type="showPassword ? 'text' : 'password'"
|
|
197
|
+
size="md"
|
|
198
|
+
autocomplete="new-password"
|
|
199
|
+
placeholder="Type it again"
|
|
200
|
+
icon="i-lucide-shield-check"
|
|
201
|
+
@keydown.enter="submit"
|
|
202
|
+
/>
|
|
203
|
+
<p
|
|
204
|
+
v-if="confirmMismatch"
|
|
205
|
+
class="text-xs text-(--ui-color-error-500)"
|
|
206
|
+
>
|
|
207
|
+
Passwords don't match.
|
|
208
|
+
</p>
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
<div
|
|
212
|
+
v-if="showInviteCode"
|
|
213
|
+
class="flex flex-col gap-1"
|
|
214
|
+
>
|
|
215
|
+
<label class="text-xs font-medium text-(--ui-text-muted)">Invite code (optional)</label>
|
|
216
|
+
<UInput
|
|
217
|
+
v-model="inviteCode"
|
|
218
|
+
size="sm"
|
|
219
|
+
placeholder="paste invite code"
|
|
220
|
+
icon="i-lucide-ticket"
|
|
221
|
+
@keydown.enter="submit"
|
|
222
|
+
/>
|
|
223
|
+
</div>
|
|
224
|
+
|
|
225
|
+
<div
|
|
226
|
+
v-if="showSignInLink"
|
|
227
|
+
class="-mt-1 text-xs"
|
|
228
|
+
>
|
|
229
|
+
<UButton
|
|
230
|
+
variant="link"
|
|
231
|
+
color="neutral"
|
|
232
|
+
size="xs"
|
|
233
|
+
label="Already have an account? Sign in"
|
|
234
|
+
@click="emit('signin')"
|
|
235
|
+
/>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
</template>
|
|
239
|
+
|
|
240
|
+
<template #footer>
|
|
241
|
+
<div class="flex items-center justify-end gap-2 w-full">
|
|
242
|
+
<UButton
|
|
243
|
+
variant="ghost"
|
|
244
|
+
color="neutral"
|
|
245
|
+
size="sm"
|
|
246
|
+
label="Cancel"
|
|
247
|
+
:disabled="loading"
|
|
248
|
+
@click="open = false"
|
|
249
|
+
/>
|
|
250
|
+
<UButton
|
|
251
|
+
color="primary"
|
|
252
|
+
size="sm"
|
|
253
|
+
icon="i-lucide-user-plus"
|
|
254
|
+
label="Create account"
|
|
255
|
+
:loading="loading"
|
|
256
|
+
:disabled="!canSubmit"
|
|
257
|
+
@click="submit"
|
|
258
|
+
/>
|
|
259
|
+
</div>
|
|
260
|
+
</template>
|
|
261
|
+
</UModal>
|
|
262
|
+
</template>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
open?: boolean;
|
|
3
|
+
loading?: boolean;
|
|
4
|
+
error?: string | null;
|
|
5
|
+
title?: string;
|
|
6
|
+
subtitle?: string;
|
|
7
|
+
/** Server-enforced minimum password length (mirrored client-side). */
|
|
8
|
+
minLength?: number;
|
|
9
|
+
/** Show optional email field. */
|
|
10
|
+
showEmail?: boolean;
|
|
11
|
+
/** Show optional display-name field. */
|
|
12
|
+
showDisplayName?: boolean;
|
|
13
|
+
/** Show optional invite-code field. */
|
|
14
|
+
showInviteCode?: boolean;
|
|
15
|
+
/** Show "Already have an account? Sign in" link. */
|
|
16
|
+
showSignInLink?: boolean;
|
|
17
|
+
};
|
|
18
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
19
|
+
submit: (payload: {
|
|
20
|
+
username: string;
|
|
21
|
+
password: string;
|
|
22
|
+
email?: string;
|
|
23
|
+
displayName?: string;
|
|
24
|
+
inviteCode?: string;
|
|
25
|
+
}) => any;
|
|
26
|
+
"update:open": (v: boolean) => any;
|
|
27
|
+
signin: () => any;
|
|
28
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
29
|
+
onSubmit?: ((payload: {
|
|
30
|
+
username: string;
|
|
31
|
+
password: string;
|
|
32
|
+
email?: string;
|
|
33
|
+
displayName?: string;
|
|
34
|
+
inviteCode?: string;
|
|
35
|
+
}) => any) | undefined;
|
|
36
|
+
"onUpdate:open"?: ((v: boolean) => any) | undefined;
|
|
37
|
+
onSignin?: (() => any) | undefined;
|
|
38
|
+
}>, {
|
|
39
|
+
subtitle: string;
|
|
40
|
+
title: string;
|
|
41
|
+
minLength: number;
|
|
42
|
+
loading: boolean;
|
|
43
|
+
showInviteCode: boolean;
|
|
44
|
+
showEmail: boolean;
|
|
45
|
+
showDisplayName: boolean;
|
|
46
|
+
showSignInLink: boolean;
|
|
47
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
48
|
+
declare const _default: typeof __VLS_export;
|
|
49
|
+
export default _default;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
open?: boolean;
|
|
3
|
+
loading?: boolean;
|
|
4
|
+
error?: string | null;
|
|
5
|
+
/** Pre-fill the token (e.g. from a query param when the email link lands here). */
|
|
6
|
+
initialToken?: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
subtitle?: string;
|
|
9
|
+
minLength?: number;
|
|
10
|
+
};
|
|
11
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
12
|
+
submit: (payload: {
|
|
13
|
+
token: string;
|
|
14
|
+
newPassword: string;
|
|
15
|
+
}) => any;
|
|
16
|
+
"update:open": (v: boolean) => any;
|
|
17
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
18
|
+
onSubmit?: ((payload: {
|
|
19
|
+
token: string;
|
|
20
|
+
newPassword: string;
|
|
21
|
+
}) => any) | undefined;
|
|
22
|
+
"onUpdate:open"?: ((v: boolean) => any) | undefined;
|
|
23
|
+
}>, {
|
|
24
|
+
subtitle: string;
|
|
25
|
+
title: string;
|
|
26
|
+
minLength: number;
|
|
27
|
+
loading: boolean;
|
|
28
|
+
initialToken: string;
|
|
29
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
open: { type: Boolean, required: false },
|
|
5
|
+
loading: { type: Boolean, required: false, default: false },
|
|
6
|
+
error: { type: [String, null], required: false },
|
|
7
|
+
initialToken: { type: String, required: false, default: "" },
|
|
8
|
+
title: { type: String, required: false, default: "Choose a new password" },
|
|
9
|
+
subtitle: { type: String, required: false, default: "Paste the token from your reset email, then set a new password." },
|
|
10
|
+
minLength: { type: Number, required: false, default: 8 }
|
|
11
|
+
});
|
|
12
|
+
const emit = defineEmits(["update:open", "submit"]);
|
|
13
|
+
const open = computed({
|
|
14
|
+
get: () => !!props.open,
|
|
15
|
+
set: (v) => emit("update:open", v)
|
|
16
|
+
});
|
|
17
|
+
const token = ref("");
|
|
18
|
+
const newPassword = ref("");
|
|
19
|
+
const confirm = ref("");
|
|
20
|
+
const showPassword = ref(false);
|
|
21
|
+
watch(() => props.open, (v) => {
|
|
22
|
+
if (!v) return;
|
|
23
|
+
token.value = props.initialToken || "";
|
|
24
|
+
newPassword.value = "";
|
|
25
|
+
confirm.value = "";
|
|
26
|
+
showPassword.value = false;
|
|
27
|
+
});
|
|
28
|
+
const passwordTooShort = computed(
|
|
29
|
+
() => newPassword.value.length > 0 && newPassword.value.length < props.minLength
|
|
30
|
+
);
|
|
31
|
+
const confirmMismatch = computed(
|
|
32
|
+
() => confirm.value.length > 0 && confirm.value !== newPassword.value
|
|
33
|
+
);
|
|
34
|
+
const canSubmit = computed(
|
|
35
|
+
() => !!token.value.trim() && newPassword.value.length >= props.minLength && confirm.value === newPassword.value && !props.loading
|
|
36
|
+
);
|
|
37
|
+
function submit() {
|
|
38
|
+
if (!canSubmit.value) return;
|
|
39
|
+
emit("submit", {
|
|
40
|
+
token: token.value.trim(),
|
|
41
|
+
newPassword: newPassword.value
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<UModal
|
|
48
|
+
v-model:open="open"
|
|
49
|
+
:title="title"
|
|
50
|
+
:ui="{ content: 'sm:max-w-md' }"
|
|
51
|
+
>
|
|
52
|
+
<template #body>
|
|
53
|
+
<div class="flex flex-col gap-4">
|
|
54
|
+
<p class="text-sm text-(--ui-text-muted)">
|
|
55
|
+
{{ subtitle }}
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
<UAlert
|
|
59
|
+
v-if="error"
|
|
60
|
+
color="error"
|
|
61
|
+
variant="soft"
|
|
62
|
+
icon="i-lucide-triangle-alert"
|
|
63
|
+
:description="error"
|
|
64
|
+
/>
|
|
65
|
+
|
|
66
|
+
<div class="flex flex-col gap-1">
|
|
67
|
+
<label class="text-xs font-medium text-(--ui-text-muted)">Reset token</label>
|
|
68
|
+
<UInput
|
|
69
|
+
v-model="token"
|
|
70
|
+
size="md"
|
|
71
|
+
autofocus
|
|
72
|
+
placeholder="paste from email"
|
|
73
|
+
icon="i-lucide-key"
|
|
74
|
+
:ui="{ base: 'font-mono' }"
|
|
75
|
+
@keydown.enter="submit"
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div class="flex flex-col gap-1">
|
|
80
|
+
<label class="text-xs font-medium text-(--ui-text-muted)">New password</label>
|
|
81
|
+
<UInput
|
|
82
|
+
v-model="newPassword"
|
|
83
|
+
:type="showPassword ? 'text' : 'password'"
|
|
84
|
+
size="md"
|
|
85
|
+
autocomplete="new-password"
|
|
86
|
+
:placeholder="`${minLength}+ characters`"
|
|
87
|
+
icon="i-lucide-lock"
|
|
88
|
+
:ui="{ trailing: 'pe-1' }"
|
|
89
|
+
@keydown.enter="submit"
|
|
90
|
+
>
|
|
91
|
+
<template #trailing>
|
|
92
|
+
<UButton
|
|
93
|
+
tabindex="-1"
|
|
94
|
+
variant="ghost"
|
|
95
|
+
color="neutral"
|
|
96
|
+
size="xs"
|
|
97
|
+
:icon="showPassword ? 'i-lucide-eye-off' : 'i-lucide-eye'"
|
|
98
|
+
:aria-label="showPassword ? 'Hide password' : 'Show password'"
|
|
99
|
+
@click="showPassword = !showPassword"
|
|
100
|
+
/>
|
|
101
|
+
</template>
|
|
102
|
+
</UInput>
|
|
103
|
+
<p
|
|
104
|
+
v-if="passwordTooShort"
|
|
105
|
+
class="text-xs text-(--ui-color-error-500)"
|
|
106
|
+
>
|
|
107
|
+
At least {{ minLength }} characters.
|
|
108
|
+
</p>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="flex flex-col gap-1">
|
|
112
|
+
<label class="text-xs font-medium text-(--ui-text-muted)">Confirm new password</label>
|
|
113
|
+
<UInput
|
|
114
|
+
v-model="confirm"
|
|
115
|
+
:type="showPassword ? 'text' : 'password'"
|
|
116
|
+
size="md"
|
|
117
|
+
autocomplete="new-password"
|
|
118
|
+
placeholder="Type it again"
|
|
119
|
+
icon="i-lucide-shield-check"
|
|
120
|
+
@keydown.enter="submit"
|
|
121
|
+
/>
|
|
122
|
+
<p
|
|
123
|
+
v-if="confirmMismatch"
|
|
124
|
+
class="text-xs text-(--ui-color-error-500)"
|
|
125
|
+
>
|
|
126
|
+
Passwords don't match.
|
|
127
|
+
</p>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</template>
|
|
131
|
+
|
|
132
|
+
<template #footer>
|
|
133
|
+
<div class="flex items-center justify-end gap-2 w-full">
|
|
134
|
+
<UButton
|
|
135
|
+
variant="ghost"
|
|
136
|
+
color="neutral"
|
|
137
|
+
size="sm"
|
|
138
|
+
label="Cancel"
|
|
139
|
+
:disabled="loading"
|
|
140
|
+
@click="open = false"
|
|
141
|
+
/>
|
|
142
|
+
<UButton
|
|
143
|
+
color="primary"
|
|
144
|
+
size="sm"
|
|
145
|
+
icon="i-lucide-rotate-ccw-key"
|
|
146
|
+
label="Set new password"
|
|
147
|
+
:loading="loading"
|
|
148
|
+
:disabled="!canSubmit"
|
|
149
|
+
@click="submit"
|
|
150
|
+
/>
|
|
151
|
+
</div>
|
|
152
|
+
</template>
|
|
153
|
+
</UModal>
|
|
154
|
+
</template>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
open?: boolean;
|
|
3
|
+
loading?: boolean;
|
|
4
|
+
error?: string | null;
|
|
5
|
+
/** Pre-fill the token (e.g. from a query param when the email link lands here). */
|
|
6
|
+
initialToken?: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
subtitle?: string;
|
|
9
|
+
minLength?: number;
|
|
10
|
+
};
|
|
11
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
12
|
+
submit: (payload: {
|
|
13
|
+
token: string;
|
|
14
|
+
newPassword: string;
|
|
15
|
+
}) => any;
|
|
16
|
+
"update:open": (v: boolean) => any;
|
|
17
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
18
|
+
onSubmit?: ((payload: {
|
|
19
|
+
token: string;
|
|
20
|
+
newPassword: string;
|
|
21
|
+
}) => any) | undefined;
|
|
22
|
+
"onUpdate:open"?: ((v: boolean) => any) | undefined;
|
|
23
|
+
}>, {
|
|
24
|
+
subtitle: string;
|
|
25
|
+
title: string;
|
|
26
|
+
minLength: number;
|
|
27
|
+
loading: boolean;
|
|
28
|
+
initialToken: string;
|
|
29
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
|
+
declare const _default: typeof __VLS_export;
|
|
31
|
+
export default _default;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
open?: boolean;
|
|
3
|
+
loading?: boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Flip to true after the consumer's submit handler resolves; flips the modal to the
|
|
6
|
+
* "we sent an email if that account exists" confirmation copy.
|
|
7
|
+
*/
|
|
8
|
+
sent?: boolean;
|
|
9
|
+
error?: string | null;
|
|
10
|
+
title?: string;
|
|
11
|
+
subtitle?: string;
|
|
12
|
+
/** Show the "Back to sign in" link in the footer. */
|
|
13
|
+
showSignInLink?: boolean;
|
|
14
|
+
};
|
|
15
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
16
|
+
submit: (payload: {
|
|
17
|
+
identifier: string;
|
|
18
|
+
}) => any;
|
|
19
|
+
"update:open": (v: boolean) => any;
|
|
20
|
+
signin: () => any;
|
|
21
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
22
|
+
onSubmit?: ((payload: {
|
|
23
|
+
identifier: string;
|
|
24
|
+
}) => any) | undefined;
|
|
25
|
+
"onUpdate:open"?: ((v: boolean) => any) | undefined;
|
|
26
|
+
onSignin?: (() => any) | undefined;
|
|
27
|
+
}>, {
|
|
28
|
+
subtitle: string;
|
|
29
|
+
title: string;
|
|
30
|
+
loading: boolean;
|
|
31
|
+
sent: boolean;
|
|
32
|
+
showSignInLink: boolean;
|
|
33
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
34
|
+
declare const _default: typeof __VLS_export;
|
|
35
|
+
export default _default;
|