@abraca/nuxt 2.0.0 → 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/AEditor.vue +5 -0
- 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/ASubPageList.d.vue.ts +66 -0
- package/dist/runtime/components/ASubPageList.vue +147 -0
- package/dist/runtime/components/ASubPageList.vue.d.ts +66 -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/AMedia.d.vue.ts +1 -1
- package/dist/runtime/components/aware/AMedia.vue.d.ts +1 -1
- 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/renderers/calendar/ACalendarToolbar.d.vue.ts +4 -4
- package/dist/runtime/components/renderers/calendar/ACalendarToolbar.vue.d.ts +4 -4
- package/dist/runtime/components/renderers/media/MediaTransportBar.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/media/MediaTransportBar.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/useEditorSuggestions.js +2 -1
- 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/svg-embed.d.ts +23 -0
- package/dist/runtime/extensions/svg-embed.js +33 -0
- package/dist/runtime/extensions/views/MetaFieldView.vue +23 -6
- package/dist/runtime/extensions/views/SvgEmbedView.d.vue.ts +4 -0
- package/dist/runtime/extensions/views/SvgEmbedView.vue +120 -0
- package/dist/runtime/extensions/views/SvgEmbedView.vue.d.ts +4 -0
- package/dist/runtime/plugin-abracadabra.client.js +58 -9
- package/dist/runtime/plugin-abracadabra.server.js +2 -0
- package/dist/runtime/plugins/core.plugin.js +8 -4
- package/dist/runtime/server/plugins/abracadabra-service.js +102 -13
- package/dist/runtime/types.d.ts +11 -0
- package/dist/runtime/utils/awareRingStyle.js +1 -1
- package/dist/runtime/utils/sanitizeSvg.d.ts +19 -0
- package/dist/runtime/utils/sanitizeSvg.js +87 -0
- package/package.json +7 -8
- 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,113 @@
|
|
|
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
|
+
sent: { type: Boolean, required: false, default: false },
|
|
7
|
+
error: { type: [String, null], required: false },
|
|
8
|
+
title: { type: String, required: false, default: "Reset your password" },
|
|
9
|
+
subtitle: { type: String, required: false, default: "Enter your username or email and we'll send you a reset link." },
|
|
10
|
+
showSignInLink: { type: Boolean, required: false, default: true }
|
|
11
|
+
});
|
|
12
|
+
const emit = defineEmits(["update:open", "submit", "signin"]);
|
|
13
|
+
const open = computed({
|
|
14
|
+
get: () => !!props.open,
|
|
15
|
+
set: (v) => emit("update:open", v)
|
|
16
|
+
});
|
|
17
|
+
const identifier = ref("");
|
|
18
|
+
watch(() => props.open, (v) => {
|
|
19
|
+
if (!v) return;
|
|
20
|
+
identifier.value = "";
|
|
21
|
+
});
|
|
22
|
+
const canSubmit = computed(
|
|
23
|
+
() => !!identifier.value.trim() && !props.loading && !props.sent
|
|
24
|
+
);
|
|
25
|
+
function submit() {
|
|
26
|
+
if (!canSubmit.value) return;
|
|
27
|
+
emit("submit", { identifier: identifier.value.trim() });
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<UModal
|
|
33
|
+
v-model:open="open"
|
|
34
|
+
:title="title"
|
|
35
|
+
:ui="{ content: 'sm:max-w-md' }"
|
|
36
|
+
>
|
|
37
|
+
<template #body>
|
|
38
|
+
<div class="flex flex-col gap-4">
|
|
39
|
+
<UAlert
|
|
40
|
+
v-if="sent"
|
|
41
|
+
color="success"
|
|
42
|
+
variant="soft"
|
|
43
|
+
icon="i-lucide-mail-check"
|
|
44
|
+
title="Check your inbox"
|
|
45
|
+
description="If an account matches that identifier, we've sent a password reset link. The link expires shortly — use it soon."
|
|
46
|
+
/>
|
|
47
|
+
|
|
48
|
+
<template v-else>
|
|
49
|
+
<p class="text-sm text-(--ui-text-muted)">
|
|
50
|
+
{{ subtitle }}
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
<UAlert
|
|
54
|
+
v-if="error"
|
|
55
|
+
color="error"
|
|
56
|
+
variant="soft"
|
|
57
|
+
icon="i-lucide-triangle-alert"
|
|
58
|
+
:description="error"
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
<div class="flex flex-col gap-1">
|
|
62
|
+
<label class="text-xs font-medium text-(--ui-text-muted)">Username or email</label>
|
|
63
|
+
<UInput
|
|
64
|
+
v-model="identifier"
|
|
65
|
+
size="md"
|
|
66
|
+
autofocus
|
|
67
|
+
autocomplete="username"
|
|
68
|
+
placeholder="your-handle or you@example.com"
|
|
69
|
+
icon="i-lucide-mail-question"
|
|
70
|
+
@keydown.enter="submit"
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div
|
|
75
|
+
v-if="showSignInLink"
|
|
76
|
+
class="-mt-1 text-xs"
|
|
77
|
+
>
|
|
78
|
+
<UButton
|
|
79
|
+
variant="link"
|
|
80
|
+
color="neutral"
|
|
81
|
+
size="xs"
|
|
82
|
+
label="Back to sign in"
|
|
83
|
+
@click="emit('signin')"
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
</template>
|
|
87
|
+
</div>
|
|
88
|
+
</template>
|
|
89
|
+
|
|
90
|
+
<template #footer>
|
|
91
|
+
<div class="flex items-center justify-end gap-2 w-full">
|
|
92
|
+
<UButton
|
|
93
|
+
variant="ghost"
|
|
94
|
+
color="neutral"
|
|
95
|
+
size="sm"
|
|
96
|
+
:label="sent ? 'Close' : 'Cancel'"
|
|
97
|
+
:disabled="loading"
|
|
98
|
+
@click="open = false"
|
|
99
|
+
/>
|
|
100
|
+
<UButton
|
|
101
|
+
v-if="!sent"
|
|
102
|
+
color="primary"
|
|
103
|
+
size="sm"
|
|
104
|
+
icon="i-lucide-mail"
|
|
105
|
+
label="Send reset link"
|
|
106
|
+
:loading="loading"
|
|
107
|
+
:disabled="!canSubmit"
|
|
108
|
+
@click="submit"
|
|
109
|
+
/>
|
|
110
|
+
</div>
|
|
111
|
+
</template>
|
|
112
|
+
</UModal>
|
|
113
|
+
</template>
|
|
@@ -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;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
loading?: boolean;
|
|
3
|
+
error?: string | null;
|
|
4
|
+
/** Flip to true after a successful set — card shows a success state. */
|
|
5
|
+
success?: boolean;
|
|
6
|
+
title?: string;
|
|
7
|
+
subtitle?: string;
|
|
8
|
+
minLength?: number;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
+
submit: (payload: {
|
|
12
|
+
password: string;
|
|
13
|
+
}) => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
onSubmit?: ((payload: {
|
|
16
|
+
password: string;
|
|
17
|
+
}) => any) | undefined;
|
|
18
|
+
}>, {
|
|
19
|
+
subtitle: string;
|
|
20
|
+
title: string;
|
|
21
|
+
success: boolean;
|
|
22
|
+
minLength: number;
|
|
23
|
+
loading: boolean;
|
|
24
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
25
|
+
declare const _default: typeof __VLS_export;
|
|
26
|
+
export default _default;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
loading: { type: Boolean, required: false, default: false },
|
|
5
|
+
error: { type: [String, null], required: false },
|
|
6
|
+
success: { type: Boolean, required: false, default: false },
|
|
7
|
+
title: { type: String, required: false, default: "Add a password" },
|
|
8
|
+
subtitle: { type: String, required: false, default: "Your account currently relies on this device's passkey. Adding a password lets you sign in from a second device or recover access if this device is lost." },
|
|
9
|
+
minLength: { type: Number, required: false, default: 8 }
|
|
10
|
+
});
|
|
11
|
+
const emit = defineEmits(["submit"]);
|
|
12
|
+
const password = ref("");
|
|
13
|
+
const confirm = ref("");
|
|
14
|
+
const showPassword = ref(false);
|
|
15
|
+
watch(() => props.success, (v) => {
|
|
16
|
+
if (!v) return;
|
|
17
|
+
password.value = "";
|
|
18
|
+
confirm.value = "";
|
|
19
|
+
showPassword.value = false;
|
|
20
|
+
});
|
|
21
|
+
const passwordTooShort = computed(
|
|
22
|
+
() => password.value.length > 0 && password.value.length < props.minLength
|
|
23
|
+
);
|
|
24
|
+
const confirmMismatch = computed(
|
|
25
|
+
() => confirm.value.length > 0 && confirm.value !== password.value
|
|
26
|
+
);
|
|
27
|
+
const canSubmit = computed(
|
|
28
|
+
() => password.value.length >= props.minLength && confirm.value === password.value && !props.loading && !props.success
|
|
29
|
+
);
|
|
30
|
+
function submit() {
|
|
31
|
+
if (!canSubmit.value) return;
|
|
32
|
+
emit("submit", { password: password.value });
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<div class="set-pw-card">
|
|
38
|
+
<div class="set-pw-head">
|
|
39
|
+
<UIcon
|
|
40
|
+
name="i-lucide-key-square"
|
|
41
|
+
class="size-5 text-(--ui-primary) shrink-0"
|
|
42
|
+
/>
|
|
43
|
+
<div class="flex-1">
|
|
44
|
+
<h4 class="set-pw-title">
|
|
45
|
+
{{ title }}
|
|
46
|
+
</h4>
|
|
47
|
+
<p class="set-pw-sub">
|
|
48
|
+
{{ subtitle }}
|
|
49
|
+
</p>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<UAlert
|
|
54
|
+
v-if="success"
|
|
55
|
+
color="success"
|
|
56
|
+
variant="soft"
|
|
57
|
+
icon="i-lucide-check"
|
|
58
|
+
title="Password set"
|
|
59
|
+
description="You can now sign in with your username and password from another device."
|
|
60
|
+
/>
|
|
61
|
+
|
|
62
|
+
<UAlert
|
|
63
|
+
v-else-if="error"
|
|
64
|
+
color="error"
|
|
65
|
+
variant="soft"
|
|
66
|
+
icon="i-lucide-triangle-alert"
|
|
67
|
+
:description="error"
|
|
68
|
+
/>
|
|
69
|
+
|
|
70
|
+
<template v-if="!success">
|
|
71
|
+
<div class="set-pw-field">
|
|
72
|
+
<label class="set-pw-label">New password</label>
|
|
73
|
+
<UInput
|
|
74
|
+
v-model="password"
|
|
75
|
+
:type="showPassword ? 'text' : 'password'"
|
|
76
|
+
size="md"
|
|
77
|
+
autocomplete="new-password"
|
|
78
|
+
:placeholder="`${minLength}+ characters`"
|
|
79
|
+
icon="i-lucide-lock"
|
|
80
|
+
:ui="{ trailing: 'pe-1' }"
|
|
81
|
+
@keydown.enter="submit"
|
|
82
|
+
>
|
|
83
|
+
<template #trailing>
|
|
84
|
+
<UButton
|
|
85
|
+
tabindex="-1"
|
|
86
|
+
variant="ghost"
|
|
87
|
+
color="neutral"
|
|
88
|
+
size="xs"
|
|
89
|
+
:icon="showPassword ? 'i-lucide-eye-off' : 'i-lucide-eye'"
|
|
90
|
+
:aria-label="showPassword ? 'Hide password' : 'Show password'"
|
|
91
|
+
@click="showPassword = !showPassword"
|
|
92
|
+
/>
|
|
93
|
+
</template>
|
|
94
|
+
</UInput>
|
|
95
|
+
<p
|
|
96
|
+
v-if="passwordTooShort"
|
|
97
|
+
class="set-pw-err"
|
|
98
|
+
>
|
|
99
|
+
At least {{ minLength }} characters.
|
|
100
|
+
</p>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div class="set-pw-field">
|
|
104
|
+
<label class="set-pw-label">Confirm</label>
|
|
105
|
+
<UInput
|
|
106
|
+
v-model="confirm"
|
|
107
|
+
:type="showPassword ? 'text' : 'password'"
|
|
108
|
+
size="md"
|
|
109
|
+
autocomplete="new-password"
|
|
110
|
+
placeholder="Type it again"
|
|
111
|
+
icon="i-lucide-shield-check"
|
|
112
|
+
@keydown.enter="submit"
|
|
113
|
+
/>
|
|
114
|
+
<p
|
|
115
|
+
v-if="confirmMismatch"
|
|
116
|
+
class="set-pw-err"
|
|
117
|
+
>
|
|
118
|
+
Passwords don't match.
|
|
119
|
+
</p>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div class="set-pw-actions">
|
|
123
|
+
<UButton
|
|
124
|
+
color="primary"
|
|
125
|
+
size="sm"
|
|
126
|
+
icon="i-lucide-key-round"
|
|
127
|
+
label="Set password"
|
|
128
|
+
:loading="loading"
|
|
129
|
+
:disabled="!canSubmit"
|
|
130
|
+
@click="submit"
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
</template>
|
|
134
|
+
</div>
|
|
135
|
+
</template>
|
|
136
|
+
|
|
137
|
+
<style scoped>
|
|
138
|
+
.set-pw-card{background:var(--ui-bg);border:1px solid var(--ui-border);border-radius:.6rem;display:flex;flex-direction:column;gap:.75rem;padding:1rem}.set-pw-head{align-items:flex-start;display:flex;gap:.6rem}.set-pw-title{color:var(--ui-text-highlighted);font-size:.875rem;font-weight:600;margin:0}.set-pw-sub{color:var(--ui-text-muted);font-size:.8125rem;line-height:1.5;margin:.2rem 0 0}.set-pw-field{display:flex;flex-direction:column;gap:.25rem}.set-pw-label{color:var(--ui-text-muted);font-size:.7rem;font-weight:500}.set-pw-err{color:var(--ui-color-error-500);font-size:.7rem;margin:0}.set-pw-actions{display:flex;justify-content:flex-end;padding-top:.25rem}
|
|
139
|
+
</style>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
loading?: boolean;
|
|
3
|
+
error?: string | null;
|
|
4
|
+
/** Flip to true after a successful set — card shows a success state. */
|
|
5
|
+
success?: boolean;
|
|
6
|
+
title?: string;
|
|
7
|
+
subtitle?: string;
|
|
8
|
+
minLength?: number;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
+
submit: (payload: {
|
|
12
|
+
password: string;
|
|
13
|
+
}) => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
onSubmit?: ((payload: {
|
|
16
|
+
password: string;
|
|
17
|
+
}) => any) | undefined;
|
|
18
|
+
}>, {
|
|
19
|
+
subtitle: string;
|
|
20
|
+
title: string;
|
|
21
|
+
success: boolean;
|
|
22
|
+
minLength: number;
|
|
23
|
+
loading: boolean;
|
|
24
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
25
|
+
declare const _default: typeof __VLS_export;
|
|
26
|
+
export default _default;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export interface SubPageListEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
type?: string;
|
|
5
|
+
meta?: {
|
|
6
|
+
icon?: string;
|
|
7
|
+
color?: string;
|
|
8
|
+
[k: string]: unknown;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
type __VLS_Props = {
|
|
12
|
+
/** Parent document whose direct children are listed. */
|
|
13
|
+
parentDocId: string;
|
|
14
|
+
/** Layout. `list` = vertical rows, `grid` = card grid, `compact` = minimal pills. Default: 'list'. */
|
|
15
|
+
layout?: 'list' | 'grid' | 'compact';
|
|
16
|
+
/** Maximum number of items shown. Omit for all. */
|
|
17
|
+
limit?: number;
|
|
18
|
+
/** Empty-state text. */
|
|
19
|
+
emptyText?: string;
|
|
20
|
+
/** Show a "New …" button at the bottom of the list. Emits `create`. */
|
|
21
|
+
showCreate?: boolean;
|
|
22
|
+
/** Label for the create button. */
|
|
23
|
+
createLabel?: string;
|
|
24
|
+
};
|
|
25
|
+
declare var __VLS_1: {}, __VLS_8: {
|
|
26
|
+
entry: SubPageListEntry;
|
|
27
|
+
}, __VLS_15: {
|
|
28
|
+
entry: SubPageListEntry;
|
|
29
|
+
}, __VLS_17: {
|
|
30
|
+
key: string;
|
|
31
|
+
entry: SubPageListEntry;
|
|
32
|
+
}, __VLS_24: {
|
|
33
|
+
key: string;
|
|
34
|
+
entry: SubPageListEntry;
|
|
35
|
+
};
|
|
36
|
+
type __VLS_Slots = {} & {
|
|
37
|
+
empty?: (props: typeof __VLS_1) => any;
|
|
38
|
+
} & {
|
|
39
|
+
item?: (props: typeof __VLS_8) => any;
|
|
40
|
+
} & {
|
|
41
|
+
'item-trailing'?: (props: typeof __VLS_15) => any;
|
|
42
|
+
} & {
|
|
43
|
+
item?: (props: typeof __VLS_17) => any;
|
|
44
|
+
} & {
|
|
45
|
+
item?: (props: typeof __VLS_24) => any;
|
|
46
|
+
};
|
|
47
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
48
|
+
open: (id: string, label: string) => any;
|
|
49
|
+
create: () => any;
|
|
50
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
51
|
+
onOpen?: ((id: string, label: string) => any) | undefined;
|
|
52
|
+
onCreate?: (() => any) | undefined;
|
|
53
|
+
}>, {
|
|
54
|
+
layout: "list" | "grid" | "compact";
|
|
55
|
+
emptyText: string;
|
|
56
|
+
showCreate: boolean;
|
|
57
|
+
createLabel: string;
|
|
58
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
59
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
60
|
+
declare const _default: typeof __VLS_export;
|
|
61
|
+
export default _default;
|
|
62
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
63
|
+
new (): {
|
|
64
|
+
$slots: S;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { useAbracadabra } from "../composables/useAbracadabra";
|
|
4
|
+
import { useChildTree } from "../composables/useChildTree";
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
parentDocId: { type: String, required: true },
|
|
7
|
+
layout: { type: String, required: false, default: "list" },
|
|
8
|
+
limit: { type: Number, required: false },
|
|
9
|
+
emptyText: { type: String, required: false, default: "No child documents yet" },
|
|
10
|
+
showCreate: { type: Boolean, required: false, default: false },
|
|
11
|
+
createLabel: { type: String, required: false, default: "New page" }
|
|
12
|
+
});
|
|
13
|
+
const emit = defineEmits(["open", "create"]);
|
|
14
|
+
const { doc: rootDoc } = useAbracadabra();
|
|
15
|
+
const tree = useChildTree(rootDoc, props.parentDocId);
|
|
16
|
+
const entries = computed(() => {
|
|
17
|
+
const all = tree.childrenOf(null);
|
|
18
|
+
return props.limit !== void 0 ? all.slice(0, props.limit) : all;
|
|
19
|
+
});
|
|
20
|
+
function defaultIcon(entry) {
|
|
21
|
+
return entry.meta?.icon ?? "i-lucide-file-text";
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<div class="a-subpage-list">
|
|
27
|
+
<!-- Empty state -->
|
|
28
|
+
<div
|
|
29
|
+
v-if="!entries.length"
|
|
30
|
+
class="a-subpage-list__empty"
|
|
31
|
+
>
|
|
32
|
+
<slot name="empty">
|
|
33
|
+
<UIcon
|
|
34
|
+
name="i-lucide-folder-open"
|
|
35
|
+
class="size-6 text-(--ui-text-dimmed) mb-2"
|
|
36
|
+
/>
|
|
37
|
+
<p class="text-sm text-(--ui-text-muted)">
|
|
38
|
+
{{ emptyText }}
|
|
39
|
+
</p>
|
|
40
|
+
</slot>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<!-- list -->
|
|
44
|
+
<ul
|
|
45
|
+
v-else-if="layout === 'list'"
|
|
46
|
+
class="flex flex-col gap-0.5"
|
|
47
|
+
>
|
|
48
|
+
<li
|
|
49
|
+
v-for="entry in entries"
|
|
50
|
+
:key="entry.id"
|
|
51
|
+
>
|
|
52
|
+
<slot
|
|
53
|
+
name="item"
|
|
54
|
+
:entry="entry"
|
|
55
|
+
>
|
|
56
|
+
<button
|
|
57
|
+
class="w-full flex items-center gap-2 px-2.5 py-1.5 rounded-md text-sm text-(--ui-text) hover:bg-(--ui-bg-elevated) transition-colors text-left"
|
|
58
|
+
type="button"
|
|
59
|
+
@click="emit('open', entry.id, entry.label)"
|
|
60
|
+
>
|
|
61
|
+
<UIcon
|
|
62
|
+
:name="defaultIcon(entry)"
|
|
63
|
+
class="size-4 shrink-0"
|
|
64
|
+
:style="entry.meta?.color ? `color: ${entry.meta.color}` : ''"
|
|
65
|
+
:class="entry.meta?.color ? '' : 'text-(--ui-text-muted)'"
|
|
66
|
+
/>
|
|
67
|
+
<span class="flex-1 truncate">{{ entry.label || "Untitled" }}</span>
|
|
68
|
+
<slot
|
|
69
|
+
name="item-trailing"
|
|
70
|
+
:entry="entry"
|
|
71
|
+
/>
|
|
72
|
+
</button>
|
|
73
|
+
</slot>
|
|
74
|
+
</li>
|
|
75
|
+
</ul>
|
|
76
|
+
|
|
77
|
+
<!-- grid -->
|
|
78
|
+
<div
|
|
79
|
+
v-else-if="layout === 'grid'"
|
|
80
|
+
class="grid grid-cols-2 sm:grid-cols-3 gap-2"
|
|
81
|
+
>
|
|
82
|
+
<slot
|
|
83
|
+
v-for="entry in entries"
|
|
84
|
+
:key="entry.id"
|
|
85
|
+
name="item"
|
|
86
|
+
:entry="entry"
|
|
87
|
+
>
|
|
88
|
+
<button
|
|
89
|
+
class="flex flex-col gap-2 p-3 rounded-md border border-(--ui-border) bg-(--ui-bg) hover:border-(--ui-border-accented) hover:bg-(--ui-bg-elevated) transition-colors text-left"
|
|
90
|
+
type="button"
|
|
91
|
+
@click="emit('open', entry.id, entry.label)"
|
|
92
|
+
>
|
|
93
|
+
<UIcon
|
|
94
|
+
:name="defaultIcon(entry)"
|
|
95
|
+
class="size-5"
|
|
96
|
+
:style="entry.meta?.color ? `color: ${entry.meta.color}` : ''"
|
|
97
|
+
:class="entry.meta?.color ? '' : 'text-(--ui-text-muted)'"
|
|
98
|
+
/>
|
|
99
|
+
<span class="text-sm font-medium text-(--ui-text-highlighted) line-clamp-2">{{ entry.label || "Untitled" }}</span>
|
|
100
|
+
</button>
|
|
101
|
+
</slot>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<!-- compact -->
|
|
105
|
+
<div
|
|
106
|
+
v-else-if="layout === 'compact'"
|
|
107
|
+
class="flex flex-wrap gap-1.5"
|
|
108
|
+
>
|
|
109
|
+
<slot
|
|
110
|
+
v-for="entry in entries"
|
|
111
|
+
:key="entry.id"
|
|
112
|
+
name="item"
|
|
113
|
+
:entry="entry"
|
|
114
|
+
>
|
|
115
|
+
<button
|
|
116
|
+
class="inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full border border-(--ui-border) bg-(--ui-bg) text-xs hover:border-(--ui-border-accented) hover:bg-(--ui-bg-elevated) transition-colors"
|
|
117
|
+
type="button"
|
|
118
|
+
@click="emit('open', entry.id, entry.label)"
|
|
119
|
+
>
|
|
120
|
+
<UIcon
|
|
121
|
+
:name="defaultIcon(entry)"
|
|
122
|
+
class="size-3"
|
|
123
|
+
:style="entry.meta?.color ? `color: ${entry.meta.color}` : ''"
|
|
124
|
+
:class="entry.meta?.color ? '' : 'text-(--ui-text-muted)'"
|
|
125
|
+
/>
|
|
126
|
+
<span class="text-(--ui-text)">{{ entry.label || "Untitled" }}</span>
|
|
127
|
+
</button>
|
|
128
|
+
</slot>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<!-- create -->
|
|
132
|
+
<div
|
|
133
|
+
v-if="showCreate"
|
|
134
|
+
class="mt-2"
|
|
135
|
+
>
|
|
136
|
+
<UButton
|
|
137
|
+
:icon="layout === 'grid' ? 'i-lucide-plus-square' : 'i-lucide-plus'"
|
|
138
|
+
:label="createLabel"
|
|
139
|
+
size="sm"
|
|
140
|
+
variant="ghost"
|
|
141
|
+
color="neutral"
|
|
142
|
+
:block="layout === 'grid'"
|
|
143
|
+
@click="emit('create')"
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
</template>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export interface SubPageListEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
type?: string;
|
|
5
|
+
meta?: {
|
|
6
|
+
icon?: string;
|
|
7
|
+
color?: string;
|
|
8
|
+
[k: string]: unknown;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
type __VLS_Props = {
|
|
12
|
+
/** Parent document whose direct children are listed. */
|
|
13
|
+
parentDocId: string;
|
|
14
|
+
/** Layout. `list` = vertical rows, `grid` = card grid, `compact` = minimal pills. Default: 'list'. */
|
|
15
|
+
layout?: 'list' | 'grid' | 'compact';
|
|
16
|
+
/** Maximum number of items shown. Omit for all. */
|
|
17
|
+
limit?: number;
|
|
18
|
+
/** Empty-state text. */
|
|
19
|
+
emptyText?: string;
|
|
20
|
+
/** Show a "New …" button at the bottom of the list. Emits `create`. */
|
|
21
|
+
showCreate?: boolean;
|
|
22
|
+
/** Label for the create button. */
|
|
23
|
+
createLabel?: string;
|
|
24
|
+
};
|
|
25
|
+
declare var __VLS_1: {}, __VLS_8: {
|
|
26
|
+
entry: SubPageListEntry;
|
|
27
|
+
}, __VLS_15: {
|
|
28
|
+
entry: SubPageListEntry;
|
|
29
|
+
}, __VLS_17: {
|
|
30
|
+
key: string;
|
|
31
|
+
entry: SubPageListEntry;
|
|
32
|
+
}, __VLS_24: {
|
|
33
|
+
key: string;
|
|
34
|
+
entry: SubPageListEntry;
|
|
35
|
+
};
|
|
36
|
+
type __VLS_Slots = {} & {
|
|
37
|
+
empty?: (props: typeof __VLS_1) => any;
|
|
38
|
+
} & {
|
|
39
|
+
item?: (props: typeof __VLS_8) => any;
|
|
40
|
+
} & {
|
|
41
|
+
'item-trailing'?: (props: typeof __VLS_15) => any;
|
|
42
|
+
} & {
|
|
43
|
+
item?: (props: typeof __VLS_17) => any;
|
|
44
|
+
} & {
|
|
45
|
+
item?: (props: typeof __VLS_24) => any;
|
|
46
|
+
};
|
|
47
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
48
|
+
open: (id: string, label: string) => any;
|
|
49
|
+
create: () => any;
|
|
50
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
51
|
+
onOpen?: ((id: string, label: string) => any) | undefined;
|
|
52
|
+
onCreate?: (() => any) | undefined;
|
|
53
|
+
}>, {
|
|
54
|
+
layout: "list" | "grid" | "compact";
|
|
55
|
+
emptyText: string;
|
|
56
|
+
showCreate: boolean;
|
|
57
|
+
createLabel: string;
|
|
58
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
59
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
60
|
+
declare const _default: typeof __VLS_export;
|
|
61
|
+
export default _default;
|
|
62
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
63
|
+
new (): {
|
|
64
|
+
$slots: S;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
@@ -2,6 +2,7 @@ type __VLS_Props = {
|
|
|
2
2
|
fieldKey: string;
|
|
3
3
|
awareness?: boolean;
|
|
4
4
|
live?: boolean;
|
|
5
|
+
followOnly?: boolean;
|
|
5
6
|
total?: boolean;
|
|
6
7
|
};
|
|
7
8
|
declare var __VLS_9: string, __VLS_10: any, __VLS_27: string, __VLS_28: any;
|
|
@@ -13,6 +14,7 @@ type __VLS_Slots = {} & {
|
|
|
13
14
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
14
15
|
awareness: boolean;
|
|
15
16
|
live: boolean;
|
|
17
|
+
followOnly: boolean;
|
|
16
18
|
total: boolean;
|
|
17
19
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
20
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { computed, ref, useAttrs, watch } from "vue";
|
|
3
3
|
import { useAAField } from "../../composables/useAAField";
|
|
4
4
|
import { useAAUIState } from "../../composables/useAAUIState";
|
|
5
|
+
import { useAAFollowPeer } from "../../composables/useAAFollowPeer";
|
|
5
6
|
import AHoverItem from "./AHoverItem.vue";
|
|
6
7
|
function itemId(item) {
|
|
7
8
|
if (item == null) return "";
|
|
@@ -18,10 +19,12 @@ const props = defineProps({
|
|
|
18
19
|
fieldKey: { type: String, required: true },
|
|
19
20
|
awareness: { type: Boolean, required: false, default: true },
|
|
20
21
|
live: { type: Boolean, required: false, default: false },
|
|
22
|
+
followOnly: { type: Boolean, required: false, default: false },
|
|
21
23
|
total: { type: Boolean, required: false, default: false }
|
|
22
24
|
});
|
|
25
|
+
const { isFollowing } = useAAFollowPeer();
|
|
23
26
|
const enableAwareness = computed(() => props.awareness || props.total);
|
|
24
|
-
const enableLive = computed(() => props.live || props.total);
|
|
27
|
+
const enableLive = computed(() => props.live || props.total || props.followOnly && isFollowing.value);
|
|
25
28
|
const attrs = useAttrs();
|
|
26
29
|
const { hoverers, focusers, hoverHandlers } = useAAField(() => props.fieldKey);
|
|
27
30
|
const liveExpanded = useAAUIState(() => `${props.fieldKey}:expanded`, { defaultValue: "" });
|
|
@@ -37,6 +40,13 @@ watch(local, (val) => {
|
|
|
37
40
|
if (!enableLive.value) return;
|
|
38
41
|
if (JSON.stringify(liveExpanded.value) !== JSON.stringify(val)) liveExpanded.value = val;
|
|
39
42
|
});
|
|
43
|
+
watch(enableLive, (now, prev) => {
|
|
44
|
+
if (!now || prev) return;
|
|
45
|
+
const incoming = liveExpanded.value;
|
|
46
|
+
if (incoming != null && JSON.stringify(local.value) !== JSON.stringify(incoming)) {
|
|
47
|
+
local.value = incoming;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
40
50
|
const ringStyle = computed(() => {
|
|
41
51
|
if (!enableAwareness.value) return void 0;
|
|
42
52
|
const focusColor = focusers.value[0]?.user?.color;
|