mirror of
https://github.com/versia-pub/frontend.git
synced 2026-03-13 03:29:16 +01:00
feat: ✨ Add settings page to configure account and preferences
This commit is contained in:
parent
633ff184e3
commit
1691daa000
21 changed files with 687 additions and 183 deletions
85
components/inputs/rich-textbox.vue
Normal file
85
components/inputs/rich-textbox.vue
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<div class="relative">
|
||||
<textarea v-bind="$attrs" ref="textarea" v-model="content"
|
||||
class="resize-none min-h-48 prose prose-invert w-full p-0 !ring-none !border-none !outline-none placeholder:text-zinc-500 bg-transparent appearance-none focus:!border-none focus:!outline-none disabled:cursor-not-allowed"
|
||||
aria-label="Compose your message" :autofocus="true"></textarea>
|
||||
<div v-if="maxCharacters"
|
||||
:class="['absolute bottom-0 right-0 p-2 text-gray-300 font-semibold text-xs', remainingCharacters < 0 && 'text-red-500']"
|
||||
aria-live="polite">
|
||||
{{ remainingCharacters }}
|
||||
</div>
|
||||
<ComposerEmojiSuggestbox :textarea="textarea" v-if="!!currentlyBeingTypedEmoji"
|
||||
:currently-typing-emoji="currentlyBeingTypedEmoji" @autocomplete="autocompleteEmoji" />
|
||||
<ComposerMentionSuggestbox :textarea="textarea" v-if="!!currentlyBeingTypedMention"
|
||||
:currently-typing-mention="currentlyBeingTypedMention" @autocomplete="autocompleteMention" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { char, createRegExp, exactly } from "magic-regexp";
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
const props = defineProps<{
|
||||
maxCharacters?: number;
|
||||
modelContent: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
"update:modelContent": [value: string];
|
||||
}>();
|
||||
|
||||
const textarea = ref<HTMLTextAreaElement | undefined>(undefined);
|
||||
const { input: content } = useTextareaAutosize({
|
||||
element: textarea,
|
||||
input: props.modelContent,
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.modelContent,
|
||||
(value) => {
|
||||
content.value = value;
|
||||
},
|
||||
);
|
||||
|
||||
watch(content, (newValue) => {
|
||||
emit("update:modelContent", newValue);
|
||||
});
|
||||
|
||||
const remainingCharacters = computed(
|
||||
() =>
|
||||
(props.maxCharacters ?? Number.POSITIVE_INFINITY) -
|
||||
(content.value?.length ?? 0),
|
||||
);
|
||||
const currentlyBeingTypedEmoji = computed(() => {
|
||||
const match = content.value?.match(partiallyTypedEmojiValidator);
|
||||
return match ? match.at(-1)?.replace(":", "") ?? "" : null;
|
||||
});
|
||||
const currentlyBeingTypedMention = computed(() => {
|
||||
const match = content.value?.match(partiallyTypedMentionValidator);
|
||||
return match ? match.at(-1)?.replace("@", "") ?? "" : null;
|
||||
});
|
||||
|
||||
const autocompleteEmoji = (emoji: string) => {
|
||||
// Replace the end of the string with the emoji
|
||||
content.value = content.value?.replace(
|
||||
createRegExp(
|
||||
exactly(":"),
|
||||
exactly(currentlyBeingTypedEmoji.value ?? "").notBefore(char),
|
||||
),
|
||||
`:${emoji}:`,
|
||||
);
|
||||
};
|
||||
|
||||
const autocompleteMention = (mention: string) => {
|
||||
// Replace the end of the string with the mention
|
||||
content.value = content.value?.replace(
|
||||
createRegExp(
|
||||
exactly("@"),
|
||||
exactly(currentlyBeingTypedMention.value ?? "").notBefore(char),
|
||||
),
|
||||
`@${mention} `,
|
||||
);
|
||||
};
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue