<!--
SPDX-FileCopyrightText: syuilo and other misskey contributors
SPDX-License-Identifier: AGPL-3.0-only
-->

<template>
<div :class="$style.root">
	<nav :class="$style.nav">
		<div :class="$style.navPath" @contextmenu.prevent.stop="() => {}">
			<XNavFolder
				:class="[$style.navPathItem, { [$style.navCurrent]: folder == null }]"
				:parentFolder="folder"
        :selectedFiles="selectedFiles"
				@move="move"
				@upload="upload"
				@removeFile="removeFile"
				@removeFolder="removeFolder"
			/>
			<template v-for="f in hierarchyFolders">
				<span :class="[$style.navPathItem, $style.navSeparator]"><i class="ti ti-chevron-right"></i></span>
				<XNavFolder
					:folder="f"
					:parentFolder="folder"
					:class="[$style.navPathItem]"
					@move="move"
					@upload="upload"
					@removeFile="removeFile"
					@removeFolder="removeFolder"
				/>
			</template>
			<span v-if="folder != null" :class="[$style.navPathItem, $style.navSeparator]"><i
				class="ti ti-chevron-right"
			></i></span>
			<span v-if="folder != null" :class="[$style.navPathItem, $style.navCurrent]">{{ folder.name }}</span>
		</div>
		<button v-if="!multiple" class="_button" :class="$style.navMenu" @click="filesSelect">複数選択モード</button>
    <span   v-if="multiple && selectedFiles.length > 0"   style="padding-right: 12px; margin-top: auto; margin-bottom: auto;opacity: 0.5;">
      ({{ number(selectedFiles.length) }})
    </span>
		<button v-if="multiple" class="_button" :class="$style.navMenu" @click="filesSelect">複数選択モード解除</button>
		<button v-if="multiple && selectedFiles.length === 0" style="padding-right: 12px;" class="_button" @click="filesAllSelect">
			全選択
		</button>
		<button v-if="multiple && selectedFiles.length !== 0" style="padding-right: 12px;" class="_button" @click="filesAllSelect">
			全選択解除
		</button>
		<button class="_button" @click="showMenu"><i class="ti ti-dots"></i></button>
	</nav>
	<div
		ref="main"
		:class="[$style.main, { [$style.uploading]: uploadings.length > 0, [$style.fetching]: fetching }]"
		@dragover.prevent.stop="onDragover"
		@dragenter="onDragenter"
		@dragleave="onDragleave"
		@drop.prevent.stop="onDrop"
		@contextmenu.stop="onContextmenu"
	>
		<div ref="contents">
			<div v-show="folders.length > 0" ref="foldersContainer" :class="$style.folders">
				<XFolder
					v-for="(f, i) in folders"
					:key="f.id"
					v-anim="i"
					:class="$style.folder"
					:folder="f"
					:selectMode="select === 'folder'"
					:isSelected="selectedFolders.some(x => x.id === f.id)"
          :selectedFiles="selectedFiles"
					@chosen="chooseFolder"
					@move="move"
					@upload="upload"
					@removeFile="removeFile"
					@removeFolder="removeFolder"
					@dragstart="isDragSource = true"
					@dragend="isDragSource = false"
				/>
				<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
				<div v-for="(n, i) in 16" :key="i" :class="$style.padding"></div>
				<MkButton v-if="moreFolders" ref="moreFolders" @click="fetchMoreFolders">{{ i18n.ts.loadMore }}</MkButton>
			</div>
			<div v-show="files.length > 0" ref="filesContainer" :class="$style.files">
				<XFile
					v-for="(file, i) in files"
					:key="file.id"
					v-anim="i"
					:class="$style.file"
					:file="file"
					:folder="folder"
					:selectMode="select === 'file'"
					:isSelected="selectedFiles.some(x => x.id === file.id)"
          @click.shift.left.exact="filesSelect"
					@chosen="chooseFile"
					@dragstart="isDragSource = true"
					@dragend="isDragSource = false"
				/>
				<!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid -->
				<div v-for="(n, i) in 16" :key="i" :class="$style.padding"></div>
				<MkButton v-show="moreFiles" ref="loadMoreFiles" @click="fetchMoreFiles">{{ i18n.ts.loadMore }}</MkButton>
			</div>
			<div v-if="files.length == 0 && folders.length == 0 && !fetching" :class="$style.empty">
				<div v-if="draghover">{{ i18n.t('empty-draghover') }}</div>
				<div v-if="!draghover && folder == null">
					<strong>{{
						i18n.ts.emptyDrive
					}}</strong><br/>{{ i18n.t('empty-drive-description') }}
				</div>
				<div v-if="!draghover && folder != null">{{ i18n.ts.emptyFolder }}</div>
			</div>
		</div>
		<MkLoading v-if="fetching"/>
	</div>
	<div v-if="draghover" :class="$style.dropzone"></div>
	<input
		ref="fileInput" style="display: none;" type="file" accept="*/*" multiple tabindex="-1"
		@change="onChangeFileInput"
	/>
</div>
</template>

<script lang="ts" setup>
import { nextTick, onActivated, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
import * as Misskey from 'misskey-js';
import MkButton from './MkButton.vue';
import XNavFolder from '@/components/MkDrive.navFolder.vue';
import XFolder from '@/components/MkDrive.folder.vue';
import XFile from '@/components/MkDrive.file.vue';
import * as os from '@/os.js';
import { useStream } from '@/stream.js';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
import { uploadFile, uploads } from '@/scripts/upload.js';
import { claimAchievement } from '@/scripts/achievements.js';
import number from "@/filters/number.js";

const props = withDefaults(defineProps<{
  initialFolder?: Misskey.entities.DriveFolder;
  type?: string;
  multiple?: boolean;
  select?: 'file' | 'folder' | null;
}>(), {
	multiple: false,
	select: null,
});

const emit = defineEmits<{
  (ev: 'selected', v: Misskey.entities.DriveFile | Misskey.entities.DriveFolder): void;
  (ev: 'change-selection', v: Misskey.entities.DriveFile[] | Misskey.entities.DriveFolder[]): void;
  (ev: 'move-root'): void;
  (ev: 'cd', v: Misskey.entities.DriveFolder | null): void;
  (ev: 'open-folder', v: Misskey.entities.DriveFolder): void;
}>();

const loadMoreFiles = shallowRef<InstanceType<typeof MkButton>>();
const fileInput = shallowRef<HTMLInputElement>();

const folder = ref<Misskey.entities.DriveFolder | null>(null);
const files = ref<Misskey.entities.DriveFile[]>([]);
const folders = ref<Misskey.entities.DriveFolder[]>([]);
const moreFiles = ref(false);
const moreFolders = ref(false);
const hierarchyFolders = ref<Misskey.entities.DriveFolder[]>([]);
const selectedFiles = ref<Misskey.entities.DriveFile[]>([]);
const selectedFolders = ref<Misskey.entities.DriveFolder[]>([]);
const uploadings = uploads;
const connection = useStream().useChannel('drive');
const keepOriginal = ref<boolean>(defaultStore.state.keepOriginalUploading); // 外部渡しが多いので$refは使わないほうがよい
const multiple = ref(props.multiple || false);
const select = ref(props.select || null);

// ドロップされようとしているか
const draghover = ref(false);

// 自身の所有するアイテムがドラッグをスタートさせたか
// (自分自身の階層にドロップできないようにするためのフラグ)
const isDragSource = ref(false);

const fetching = ref(true);

const ilFilesObserver = new IntersectionObserver(
	(entries) => entries.some((entry) => entry.isIntersecting) && !fetching.value && moreFiles.value && fetchMoreFiles(),
);

watch(folder, () => emit('cd', folder.value));

function onStreamDriveFileCreated(file: Misskey.entities.DriveFile) {
	addFile(file, true);
}

function onStreamDriveFileUpdated(file: Misskey.entities.DriveFile) {
	const current = folder.value ? folder.value.id : null;
	if (current !== file.folderId) {
		removeFile(file);
	} else {
		addFile(file, true);
	}
}

function onStreamDriveFileDeleted(fileId: string) {
	removeFile(fileId);
}

function onStreamDriveFolderCreated(createdFolder: Misskey.entities.DriveFolder) {
	addFolder(createdFolder, true);
}

function onStreamDriveFolderUpdated(updatedFolder: Misskey.entities.DriveFolder) {
	const current = folder.value ? folder.value.id : null;
	if (current !== updatedFolder.parentId) {
		removeFolder(updatedFolder);
	} else {
		addFolder(updatedFolder, true);
	}
}

function onStreamDriveFolderDeleted(folderId: string) {
	removeFolder(folderId);
}

function onDragover(ev: DragEvent): any {
	if (!ev.dataTransfer) return;

	// ドラッグ元が自分自身の所有するアイテムだったら
	if (isDragSource.value) {
		// 自分自身にはドロップさせない
		ev.dataTransfer.dropEffect = 'none';
		return;
	}

	const isFile = ev.dataTransfer.items[0].kind === 'file';
	const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
	const isDriveFolder = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FOLDER_;
	if (isFile || isDriveFile || isDriveFolder) {
		switch (ev.dataTransfer.effectAllowed) {
			case 'all':
			case 'uninitialized':
			case 'copy':
			case 'copyLink':
			case 'copyMove':
				ev.dataTransfer.dropEffect = 'copy';
				break;
			case 'linkMove':
			case 'move':
				ev.dataTransfer.dropEffect = 'move';
				break;
			default:
				ev.dataTransfer.dropEffect = 'none';
				break;
		}
	} else {
		ev.dataTransfer.dropEffect = 'none';
	}

	return false;
}

function onDragenter() {
	if (!isDragSource.value) draghover.value = true;
}

function onDragleave() {
	draghover.value = false;
}

function onDrop(ev: DragEvent): any {
	draghover.value = false;

	if (!ev.dataTransfer) return;

	// ドロップされてきたものがファイルだったら
	if (ev.dataTransfer.files.length > 0) {
		for (const file of Array.from(ev.dataTransfer.files)) {
			upload(file, folder.value);
		}
		return;
	}

	//#region ドライブのファイル
	const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
	if (driveFile != null && driveFile !== '') {
		const file = JSON.parse(driveFile);
		if (files.value.some(f => f.id === file.id)) return;
		removeFile(file.id);
		os.api('drive/files/update', {
			fileId: file.id,
			folderId: folder.value ? folder.value.id : null,
		});
	}
	//#endregion

	//#region ドライブのフォルダ
	const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
	if (driveFolder != null && driveFolder !== '') {
		const droppedFolder = JSON.parse(driveFolder);

		// 移動先が自分自身ならreject
		if (folder.value && droppedFolder.id === folder.value.id) return false;
		if (folders.value.some(f => f.id === droppedFolder.id)) return false;
		removeFolder(droppedFolder.id);
		os.api('drive/folders/update', {
			folderId: droppedFolder.id,
			parentId: folder.value ? folder.value.id : null,
		}).then(() => {
			// noop
		}).catch(err => {
			switch (err.code) {
				case 'RECURSIVE_NESTING':
					claimAchievement('driveFolderCircularReference');
					os.alert({
						type: 'error',
						title: i18n.ts.unableToProcess,
						text: i18n.ts.circularReferenceFolder,
					});
					break;
				default:
					os.alert({
						type: 'error',
						text: i18n.ts.somethingHappened,
					});
			}
		});
	}
	//#endregion
}

function selectLocalFile() {
	fileInput.value?.click();
}

function urlUpload() {
	os.inputText({
		title: i18n.ts.uploadFromUrl,
		type: 'url',
		placeholder: i18n.ts.uploadFromUrlDescription,
	}).then(({ canceled, result: url }) => {
		if (canceled || !url) return;
		os.api('drive/files/upload-from-url', {
			url: url,
			folderId: folder.value ? folder.value.id : undefined,
		});

		os.alert({
			title: i18n.ts.uploadFromUrlRequested,
			text: i18n.ts.uploadFromUrlMayTakeTime,
		});
	});
}

function createFolder() {
	os.inputText({
		title: i18n.ts.createFolder,
		placeholder: i18n.ts.folderName,
	}).then(({ canceled, result: name }) => {
		if (canceled) return;
		os.api('drive/folders/create', {
			name: name,
			parentId: folder.value ? folder.value.id : undefined,
		}).then(createdFolder => {
			addFolder(createdFolder, true);
		});
	});
}

function renameFolder(folderToRename: Misskey.entities.DriveFolder) {
	os.inputText({
		title: i18n.ts.renameFolder,
		placeholder: i18n.ts.inputNewFolderName,
		default: folderToRename.name,
	}).then(({ canceled, result: name }) => {
		if (canceled) return;
		os.api('drive/folders/update', {
			folderId: folderToRename.id,
			name: name,
		}).then(updatedFolder => {
			// FIXME: 画面を更新するために自分自身に移動
			move(updatedFolder);
		});
	});
}

function deleteFolder(folderToDelete: Misskey.entities.DriveFolder) {
	os.api('drive/folders/delete', {
		folderId: folderToDelete.id,
	}).then(() => {
		// 削除時に親フォルダに移動
		move(folderToDelete.parentId);
	}).catch(err => {
		switch (err.id) {
			case 'b0fc8a17-963c-405d-bfbc-859a487295e1':
				os.alert({
					type: 'error',
					title: i18n.ts.unableToDelete,
					text: i18n.ts.hasChildFilesOrFolders,
				});
				break;
			default:
				os.alert({
					type: 'error',
					text: i18n.ts.unableToDelete,
				});
		}
	});
}

function onChangeFileInput() {
	if (!fileInput.value?.files) return;
	for (const file of Array.from(fileInput.value.files)) {
		upload(file, folder.value);
	}
}

function upload(file: File, folderToUpload?: Misskey.entities.DriveFolder | null) {
	uploadFile(file, (folderToUpload && typeof folderToUpload === 'object') ? folderToUpload.id : null, undefined, keepOriginal.value).then(res => {
		addFile(res, true);
	});
}

function chooseFile(file: Misskey.entities.DriveFile) {
	const isAlreadySelected = selectedFiles.value.some(f => f.id === file.id);
	if (multiple.value) {
		if (isAlreadySelected) {
			selectedFiles.value = selectedFiles.value.filter(f => f.id !== file.id);
		} else {
			selectedFiles.value.push(file);
		}
		emit('change-selection', selectedFiles.value);
	} else {
		if (isAlreadySelected) {
			emit('selected', file);
		} else {
			selectedFiles.value = [file];
			emit('change-selection', [file]);
		}
	}
}

function chooseFolder(folderToChoose: Misskey.entities.DriveFolder) {
	const isAlreadySelected = selectedFolders.value.some(f => f.id === folderToChoose.id);
	if (multiple.value) {
		if (isAlreadySelected) {
			selectedFolders.value = selectedFolders.value.filter(f => f.id !== folderToChoose.id);
		} else {
			selectedFolders.value.push(folderToChoose);
		}
		emit('change-selection', selectedFolders.value);
	} else {
		if (isAlreadySelected) {
			emit('selected', folderToChoose);
		} else {
			selectedFolders.value = [folderToChoose];
			emit('change-selection', [folderToChoose]);
		}
	}
}

function move(target?: Misskey.entities.DriveFolder) {
	if (!target) {
		goRoot();
		return;
	} else if (typeof target === 'object') {
		target = target.id;
	}

	fetching.value = true;

	os.api('drive/folders/show', {
		folderId: target,
	}).then(folderToMove => {
		folder.value = folderToMove;
		hierarchyFolders.value = [];

		const dive = folderToDive => {
			hierarchyFolders.value.unshift(folderToDive);
			if (folderToDive.parent) dive(folderToDive.parent);
		};

		if (folderToMove.parent) dive(folderToMove.parent);

		emit('open-folder', folderToMove);
		fetch();
	});
}

function addFolder(folderToAdd: Misskey.entities.DriveFolder, unshift = false) {
	const current = folder.value ? folder.value.id : null;
	if (current !== folderToAdd.parentId) return;

	if (folders.value.some(f => f.id === folderToAdd.id)) {
		const exist = folders.value.map(f => f.id).indexOf(folderToAdd.id);
		folders.value[exist] = folderToAdd;
		return;
	}

	if (unshift) {
		folders.value.unshift(folderToAdd);
	} else {
		folders.value.push(folderToAdd);
	}
}

function addFile(fileToAdd: Misskey.entities.DriveFile, unshift = false) {
	const current = folder.value ? folder.value.id : null;
	if (current !== fileToAdd.folderId) return;

	if (files.value.some(f => f.id === fileToAdd.id)) {
		const exist = files.value.map(f => f.id).indexOf(fileToAdd.id);
		files.value[exist] = fileToAdd;
		return;
	}

	if (unshift) {
		files.value.unshift(fileToAdd);
	} else {
		files.value.push(fileToAdd);
	}
}

function removeFolder(folderToRemove: Misskey.entities.DriveFolder | string) {
	const folderIdToRemove = typeof folderToRemove === 'object' ? folderToRemove.id : folderToRemove;
	folders.value = folders.value.filter(f => f.id !== folderIdToRemove);
}

function removeFile(file: Misskey.entities.DriveFile | string) {
	const fileId = typeof file === 'object' ? file.id : file;
	files.value = files.value.filter(f => f.id !== fileId);
  selectedFiles.value = selectedFiles.value.filter(f => f.id !== fileId);
}

function appendFile(file: Misskey.entities.DriveFile) {
	addFile(file);
}

function appendFolder(folderToAppend: Misskey.entities.DriveFolder) {
	addFolder(folderToAppend);
}

/*
function prependFile(file: Misskey.entities.DriveFile) {
	addFile(file, true);
}

function prependFolder(folderToPrepend: Misskey.entities.DriveFolder) {
	addFolder(folderToPrepend, true);
}
*/
function goRoot() {
	// 既にrootにいるなら何もしない
	if (folder.value == null) return;

	folder.value = null;
	hierarchyFolders.value = [];
	emit('move-root');
	fetch();
}

async function fetch() {
	folders.value = [];
	files.value = [];
	moreFolders.value = false;
	moreFiles.value = false;
	fetching.value = true;

	const foldersMax = 30;
	const filesMax = 30;

	const foldersPromise = os.api('drive/folders', {
		folderId: folder.value ? folder.value.id : null,
		limit: foldersMax + 1,
	}).then(fetchedFolders => {
		if (fetchedFolders.length === foldersMax + 1) {
			moreFolders.value = true;
			fetchedFolders.pop();
		}
		return fetchedFolders;
	});

	const filesPromise = os.api('drive/files', {
		folderId: folder.value ? folder.value.id : null,
		type: props.type,
		limit: filesMax + 1,
	}).then(fetchedFiles => {
		if (fetchedFiles.length === filesMax + 1) {
			moreFiles.value = true;
			fetchedFiles.pop();
		}
		return fetchedFiles;
	});

	const [fetchedFolders, fetchedFiles] = await Promise.all([foldersPromise, filesPromise]);

	for (const x of fetchedFolders) appendFolder(x);
	for (const x of fetchedFiles) appendFile(x);

	fetching.value = false;
}

function fetchMoreFolders() {
	fetching.value = true;

	const max = 30;

	os.api('drive/folders', {
		folderId: folder.value ? folder.value.id : null,
		type: props.type,
		untilId: folders.value.at(-1)?.id,
		limit: max + 1,
	}).then(folders => {
		if (folders.length === max + 1) {
			moreFolders.value = true;
			folders.pop();
		} else {
			moreFolders.value = false;
		}
		for (const x of folders) appendFolder(x);
		fetching.value = false;
	});
}

function fetchMoreFiles() {
	fetching.value = true;

	const max = 30;

	// ファイル一覧取得
	os.api('drive/files', {
		folderId: folder.value ? folder.value.id : null,
		type: props.type,
		untilId: files.value.at(-1)?.id,
		limit: max + 1,
	}).then(files => {
		if (files.length === max + 1) {
			moreFiles.value = true;
			files.pop();
		} else {
			moreFiles.value = false;
		}
		for (const x of files) appendFile(x);
		fetching.value = false;
	});
}

function getMenu() {
	return [{
		type: 'switch',
		text: i18n.ts.keepOriginalUploading,
		ref: keepOriginal,
	}, null, {
		text: i18n.ts.addFile,
		type: 'label',
	}, {
		text: i18n.ts.upload,
		icon: 'ti ti-upload',
		action: () => {
			selectLocalFile();
		},
	}, {
		text: i18n.ts.fromUrl,
		icon: 'ti ti-link',
		action: () => {
			urlUpload();
		},
	}, null, {
		text: folder.value ? folder.value.name : i18n.ts.drive,
		type: 'label',
	}, folder.value ? {
		text: i18n.ts.renameFolder,
		icon: 'ti ti-forms',
		action: () => {
			renameFolder(folder.value);
		},
	} : undefined, folder.value ? {
		text: i18n.ts.deleteFolder,
		icon: 'ti ti-trash',
		action: () => {
			deleteFolder(folder.value as Misskey.entities.DriveFolder);
		},
	} : undefined, {
		text: i18n.ts.createFolder,
		icon: 'ti ti-folder-plus',
		action: () => {
			createFolder();
		},
	}];
}

async function isSensitive(Files, isSensitive: boolean) {
	const { canceled } = await os.confirm({
		type: 'warning',
		text: i18n.t(isSensitive ? 'driveFilesSensitiveonConfirm' : 'driveFilesSensitiveoffConfirm', { name: Files.length }),
	});

	if (canceled) return;
	Files.forEach((file) => {
		os.api('drive/files/update', {
			fileId: file.id,
			isSensitive,
		});
	});
}

async function fileDelete(Files) {
	const { canceled } = await os.confirm({
		type: 'warning',
		text: i18n.t('driveFilesDeleteConfirm', { name: Files.length }),
	});

	if (canceled) return;
	Files.forEach((file) => {
		os.api('drive/files/delete', {
			fileId: file.id,
		});
	});
}

function getFilesMenu(Files) {
	return [{
		text: i18n.ts.createNoteFromTheFile,
		icon: 'ti ti-pencil',
		action: () => {
			if (Files.length >= 16) {
				os.confirm({
					type: 'warning',
					text: '16ファイル以上添付しようとしています',
				});
				return;
			} else {
				os.post({
					initialFiles: [...Files],
				});
			}
		},
	}, {
		text: i18n.ts.unmarkAsSensitive,
		icon: 'ti ti-eye',
		action: () => {
			isSensitive(Files, false);
		},
	}, {
		text: i18n.ts.markAsSensitive,
		icon: 'ti ti-eye-exclamation',
		action: () => {
			isSensitive(Files, true);
		},
	}, {
		text: i18n.ts.delete,
		icon: 'ti ti-trash',
		danger: true,
		action: () => {
			fileDelete(Files);
		},
	}];
}

function filesSelect() {
	multiple.value = !multiple.value;
	select.value = (select.value === null) ? 'file' : null;
	selectedFiles.value = [];
}

function filesAllSelect() {
	if (selectedFiles.value.length === 0) {
		selectedFiles.value = files.value;
	} else {
		selectedFiles.value = [];
	}
}

function showMenu(ev: MouseEvent) {
	if (selectedFiles.value.length === 0) {
		os.popupMenu(getMenu(), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
	} else {
		os.popupMenu(getFilesMenu(selectedFiles.value), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
	}
}

function onContextmenu(ev: MouseEvent) {
	os.contextMenu(getMenu(), ev);
}

onMounted(() => {
	if (defaultStore.state.enableInfiniteScroll && loadMoreFiles.value) {
		nextTick(() => {
			ilFilesObserver.observe(loadMoreFiles.value?.$el);
		});
	}

	connection.on('fileCreated', onStreamDriveFileCreated);
	connection.on('fileUpdated', onStreamDriveFileUpdated);
	connection.on('fileDeleted', onStreamDriveFileDeleted);
	connection.on('folderCreated', onStreamDriveFolderCreated);
	connection.on('folderUpdated', onStreamDriveFolderUpdated);
	connection.on('folderDeleted', onStreamDriveFolderDeleted);

	if (props.initialFolder) {
		move(props.initialFolder);
	} else {
		fetch();
	}
});

onActivated(() => {
	if (defaultStore.state.enableInfiniteScroll) {
		nextTick(() => {
			ilFilesObserver.observe(loadMoreFiles.value?.$el);
		});
	}
});

onBeforeUnmount(() => {
	connection.dispose();
	ilFilesObserver.disconnect();
});
</script>

<style lang="scss" module>
.root {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.nav {
  display: flex;
  top: 0;
  position: sticky;
  z-index: 1000;
  background-color: var(--bg);
  width: 100%;
  padding: 0 8px;
  box-sizing: border-box;
  overflow: auto;
  font-size: 0.9em;
  box-shadow: 0 1px 0 var(--divider);
  user-select: none;
}

.navPath {
  display: inline-block;
  vertical-align: bottom;
  line-height: 42px;
  white-space: nowrap;
}

.navPathItem {
  display: inline-block;
  margin: 0;
  padding: 0 8px;
  line-height: 42px;
  cursor: pointer;

  &:hover {
    text-decoration: underline;
  }

  &.navCurrent {
    font-weight: bold;
    cursor: default;

    &:hover {
      text-decoration: none;
    }
  }

  &.navSeparator {
    margin: 0;
    padding: 0;
    opacity: 0.5;
    cursor: default;
  }
}

.navMenu {
  margin-left: auto;
  padding: 0 12px;
}

.main {
  flex: 1;
  overflow: auto;
  padding: var(--margin);
  user-select: none;

  &.fetching {
    cursor: wait !important;
    opacity: 0.5;
    pointer-events: none;
  }

  &.uploading {
    height: calc(100% - 38px - 100px);
  }
}

.folders,
.files {
  display: flex;
  flex-wrap: wrap;
}

.folder,
.file {
  flex-grow: 1;
  width: 128px;
  margin: 4px;
  box-sizing: border-box;
}

.padding {
  flex-grow: 1;
  pointer-events: none;
  width: 128px + 8px;
}

.empty {
  padding: 16px;
  text-align: center;
  pointer-events: none;
  opacity: 0.5;
}

.dropzone {
  position: absolute;
  left: 0;
  top: 38px;
  width: 100%;
  height: calc(100% - 38px);
  border: dashed 2px var(--focus);
  pointer-events: none;
}
</style>
