diff --git a/config.toml b/config.toml index 27bd340..140263e 100644 --- a/config.toml +++ b/config.toml @@ -11,10 +11,10 @@ udp_port = 8080 [database] # DSN for database # SQLite -#url = "sqlite://oxspeak.db" +url = "sqlite://oxspeak.db" #url = "sqlite::memory:" # PostgreSQL -url = "postgresql://oxspeak:oxspeak@localhost:5432/oxspeak" +#url = "postgresql://oxspeak:oxspeak@localhost:5432/oxspeak" # MySQL # url = "mysql://user:passwd@localhost:3306/db_name" diff --git a/frontend/src/components/EmojiPicker.vue b/frontend/src/components/EmojiPicker.vue new file mode 100644 index 0000000..6544712 --- /dev/null +++ b/frontend/src/components/EmojiPicker.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/frontend/src/components/server/ServerSettingsDialog.vue b/frontend/src/components/server/ServerSettingsDialog.vue index 02ec58e..a870fb2 100644 --- a/frontend/src/components/server/ServerSettingsDialog.vue +++ b/frontend/src/components/server/ServerSettingsDialog.vue @@ -7,6 +7,7 @@ import {useUserStore} from '@/stores/user' import {usePermissions} from '@/composables/usePermissions' import {toServerPermissionMask, type ServerPermissionMask, type ServerUserPermission} from '@/types/permissions' import ServerPermissionEditor from '@/components/permissions/ServerPermissionEditor.vue' +import {useEmojiStore} from '@/stores/emoji' const props = defineProps<{modelValue: boolean; serverId: string; serverName: string}>() const emit = defineEmits<{ 'update:modelValue': [value: boolean] }>() @@ -14,6 +15,7 @@ const serverStore = useServerStore() const roleStore = useRoleStore() const userStore = useUserStore() const permissionsApi = usePermissions() +const emojiStore = useEmojiStore() const {roles} = storeToRefs(roleStore) const activeTab = ref('general') const selectedRoleId = ref(null) @@ -26,12 +28,18 @@ const roleForm = ref('') const rolePermissions = ref(toServerPermissionMask(0)) const memberPermissions = ref(toServerPermissionMask(0)) const userPermissions = ref>({}) +const emojiName = ref('') +const emojiFile = ref(null) +const emojiPreviewUrl = ref(null) +const emojiFileInput = ref(null) +const emojiSaving = ref(false) const selectedRole = computed(() => roles.value.find(role => role.id === selectedRoleId.value) || null) const selectedMembers = computed(() => selectedRoleId.value ? roleStore.members[selectedRoleId.value] || [] : []) const availableUsers = computed(() => userStore.users.filter(user => !selectedMembers.value.some(member => member.id === user.id))) const memberToAdd = ref(null) const selectedUser = computed(() => userStore.users.find(user => user.id === selectedUserId.value) || null) +const serverEmojis = computed(() => emojiStore.emojis.filter(emoji => emoji.server_id === props.serverId && emoji.emoji_type === 'custom')) watch(() => props.modelValue, async open => { if (open) await load() @@ -59,10 +67,11 @@ async function load() { error.value = null name.value = props.serverName try { - const [server, , , permissions] = await Promise.all([ + const [server, , , , permissions] = await Promise.all([ serverStore.fetchServer(props.serverId), roleStore.fetchRoles(props.serverId), userStore.fetchUsers(props.serverId), + emojiStore.fetchEmojis(props.serverId, true), permissionsApi.listServerUserPermissions(props.serverId), ]) name.value = server.name @@ -73,6 +82,37 @@ async function load() { } finally { loading.value = false } } + +function selectEmojiFile(event: Event) { + if (emojiPreviewUrl.value) URL.revokeObjectURL(emojiPreviewUrl.value) + emojiFile.value = (event.target as HTMLInputElement).files?.[0] ?? null + emojiPreviewUrl.value = emojiFile.value ? URL.createObjectURL(emojiFile.value) : null +} + +async function createEmoji() { + if (!emojiName.value.trim() || !emojiFile.value) return + emojiSaving.value = true + error.value = null + try { + await emojiStore.createCustomEmoji(props.serverId, emojiName.value.trim(), emojiFile.value) + emojiName.value = '' + emojiFile.value = null + if (emojiPreviewUrl.value) URL.revokeObjectURL(emojiPreviewUrl.value) + emojiPreviewUrl.value = null + if (emojiFileInput.value) emojiFileInput.value.value = '' + } catch (e) { + error.value = e instanceof Error ? e.message : 'Erreur de création de l’émoji' + } finally { emojiSaving.value = false } +} + +async function deleteEmoji(id: string) { + if (!window.confirm('Supprimer cet émoji personnalisé ?')) return + emojiSaving.value = true + error.value = null + try { await emojiStore.deleteEmoji(id) } + catch (e) { error.value = e instanceof Error ? e.message : 'Erreur de suppression de l’émoji' } + finally { emojiSaving.value = false } +} async function saveServer() { if (!name.value.trim()) return saving.value = true @@ -140,6 +180,7 @@ async function resetMemberPermissions() { + @@ -177,7 +218,7 @@ async function resetMemberPermissions() { -