diff --git a/src/components/Main/MainView/MessageElement/MessageTools.vue b/src/components/Main/MainView/MessageElement/MessageTools.vue index b0a595e16..7db50641a 100644 --- a/src/components/Main/MainView/MessageElement/MessageTools.vue +++ b/src/components/Main/MainView/MessageElement/MessageTools.vue @@ -61,6 +61,14 @@ :class="$style.icon" @click="toggleStampPicker" /> + import { computed, ref } from 'vue' -import type { StampId, MessageId } from '/@/types/entity-ids' +import type { StampId, MessageId, ClipFolderId } from '/@/types/entity-ids' import { useStampPickerInvoker } from '/@/store/ui/stampPicker' import { useResponsiveStore } from '/@/store/ui/responsive' import apis from '/@/lib/apis' @@ -95,6 +103,7 @@ import AStamp from '/@/components/UI/AStamp.vue' import MessageContextMenu from './MessageContextMenu.vue' import useToggle from '/@/composables/utils/useToggle' import { useStampHistory } from '/@/store/domain/stampHistory' +import { useCreateClip } from '/@/composables/clips/createClip' const props = withDefaults( defineProps<{ @@ -169,6 +178,24 @@ const onDotsClick = (e: MouseEvent) => { }) } +const DEFAULT_CLIP_FOLDER_ID = '201fcb38-3dbe-4a53-8c0c-37b47bed9985' // FIXME: あとで直す +const clippingFolderIds = ref(new Set()) +const isClipped = computed(() => + clippingFolderIds.value.has(DEFAULT_CLIP_FOLDER_ID) +) + +apis.getMessageClips(props.messageId).then(res => { + clippingFolderIds.value = new Set(res.data.map(c => c.folderId)) +}) +const clipIconName = computed(() => { + return isClipped.value ? 'bookmark-check' : 'bookmark' +}) + +const { toggleClip } = useCreateClip(props.messageId, clippingFolderIds) +const openClipCreateModal = () => { + toggleClip(DEFAULT_CLIP_FOLDER_ID) +} + const { isMobile } = useResponsiveStore() const { value: showQuickReaction, toggle: toggleQuickReaction } = useToggle( @@ -231,6 +258,9 @@ const { value: showQuickReaction, toggle: toggleQuickReaction } = useToggle( &:hover { @include background-secondary; } + &[data-clipped] { + @include color-accent-primary; + } } .stampListItem { diff --git a/src/components/Modal/ClipCreateModal/ClipCreateModal.vue b/src/components/Modal/ClipCreateModal/ClipCreateModal.vue index 025f529c2..90926378b 100644 --- a/src/components/Modal/ClipCreateModal/ClipCreateModal.vue +++ b/src/components/Modal/ClipCreateModal/ClipCreateModal.vue @@ -4,71 +4,31 @@ - - diff --git a/src/components/Modal/ClipCreateModal/ClipFolderNew.vue b/src/components/Modal/ClipCreateModal/ClipFolderNew.vue new file mode 100644 index 000000000..c5921dcbb --- /dev/null +++ b/src/components/Modal/ClipCreateModal/ClipFolderNew.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/src/composables/clips/createClip.ts b/src/composables/clips/createClip.ts new file mode 100644 index 000000000..afa73a1af --- /dev/null +++ b/src/composables/clips/createClip.ts @@ -0,0 +1,44 @@ +import type { Ref } from 'vue' +import apis from '/@/lib/apis' +import type { MessageId, ClipFolderId } from '/@/types/entity-ids' +import { useToastStore } from '/@/store/ui/toast' +import type { AxiosError } from 'axios' + +export const useCreateClip = ( + messageId: MessageId, + isSelected: Ref> +) => { + const { addSuccessToast, addErrorToast } = useToastStore() + + const createClip = async (clipFolderId: ClipFolderId) => { + try { + await apis.clipMessage(clipFolderId, { + messageId: messageId + }) + isSelected.value.add(clipFolderId) + addSuccessToast('クリップフォルダに追加しました') + } catch (e) { + if ((e as AxiosError).response?.status === 409) { + isSelected.value.add(clipFolderId) + addErrorToast('すでに追加されています') + return + } else { + addErrorToast('追加に失敗しました') + } + throw e + } + } + const deleteClip = async (clipFolderId: ClipFolderId) => { + await apis.unclipMessage(clipFolderId, messageId) + isSelected.value.delete(clipFolderId) + addSuccessToast('クリップフォルダから削除しました') + } + const toggleClip = async (clipFolderId: ClipFolderId) => { + if (isSelected.value.has(clipFolderId)) { + await deleteClip(clipFolderId) + } else { + await createClip(clipFolderId) + } + } + return { toggleClip } +}