原本的UI确实有那么一点点的丑,拿claude3.7重新糊了个UI,作者大大可看看是否有什么问题
(因为是AI一把梭哈,所以UI可能还是有点小问题的)

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>数据中转站</title>
	<style>
		@import url('https://fonts.googleapis.com/css2?family=SF+Pro+Display:wght@300;400;500;600&display=swap');
		:root {
			--background-light: #ffffff;
			--text-light: #1d1d1f;
			--secondary-light: #6e6e73;
			--border-light: rgba(0, 0, 0, 0.1);
			--card-hover-light: rgba(0, 0, 0, 0.03);
			--card-select-light: rgba(0, 0, 0, 0.05);
			--tab-inactive-light: rgba(0, 0, 0, 0.05);
			--button-hover-light: rgba(0, 0, 0, 0.06);
			--accent-light: #0071e3;
			--danger-light: #ff3b30;
			--shadow-light: 0 1px 5px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);
			/* Dark mode colors */
			--background-dark: #1d1d1f;
			--text-dark: #f5f5f7;
			--secondary-dark: #a1a1a6;
			--border-dark: rgba(255, 255, 255, 0.15);
			--card-hover-dark: rgba(255, 255, 255, 0.05);
			--card-select-dark: rgba(255, 255, 255, 0.08);
			--tab-inactive-dark: rgba(255, 255, 255, 0.08);
			--button-hover-dark: rgba(255, 255, 255, 0.1);
			--accent-dark: #2997ff;
			--danger-dark: #ff453a;
			--shadow-dark: 0 1px 5px rgba(0, 0, 0, 0.2);
			/* Default theme */
			--background: var(--background-light);
			--text: var(--text-light);
			--secondary: var(--secondary-light);
			--border: var(--border-light);
			--card-hover: var(--card-hover-light);
			--card-select: var(--card-select-light);
			--tab-inactive: var(--tab-inactive-light);
			--button-hover: var(--button-hover-light);
			--accent: var(--accent-light);
			--danger: var(--danger-light);
			--shadow: var(--shadow-light);
			/* Animation timing */
			--transition-fast: 0.15s;
			--transition-medium: 0.25s;
			--transition-slow: 0.4s;
			/* Spacing */
			--spacing-xs: 4px;
			--spacing-sm: 8px;
			--spacing-md: 16px;
			--spacing-lg: 24px;
			--spacing-xl: 32px;
			/* Border radius */
			--radius-sm: 6px;
			--radius-md: 8px;
			--radius-lg: 12px;
		}
		::-webkit-scrollbar {
			width: 8px;
			height: 8px;
		}
		::-webkit-scrollbar-thumb {
			background: rgba(0, 0, 0, 0.15);
			border-radius: 8px;
		}
		.dark::-webkit-scrollbar-thumb {
			background: rgba(255, 255, 255, 0.2);
		}
		::-webkit-scrollbar-thumb:hover {
			background: rgba(0, 0, 0, 0.25);
		}
		.dark::-webkit-scrollbar-thumb:hover {
			background: rgba(255, 255, 255, 0.3);
		}
		::-webkit-scrollbar-track {
			background: transparent;
		}
		html,
		body {
			margin: 0;
			height: 100%;
			width: 100%;
			font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
			color: var(--text);
			background-color: var(--background);
			font-size: 14px;
			line-height: 1.5;
			-webkit-font-smoothing: antialiased;
			-moz-osx-font-smoothing: grayscale;
			transition: background-color var(--transition-medium), color var(--transition-medium);
		}
		body {
			display: flex;
			flex-direction: column;
		}
		#tab-bar {
			display: flex;
			justify-content: space-between;
			align-items: center;
			padding: var(--spacing-xs) var(--spacing-sm);
			backdrop-filter: blur(10px);
			-webkit-backdrop-filter: blur(10px);
			background-color: rgba(255, 255, 255, 0.8);
			border-bottom: 1px solid var(--border);
            position: sticky;
            top: 0;
            z-index: 100;
		}
		.dark #tab-bar {
			background-color: rgba(29, 29, 31, 0.85);
		}
		#tab-bar,
		#tool-menu {
			border-bottom: 1px solid var(--border);
			transition: border-color var(--transition-medium);
		}
		#tool-menu {
			display: none;
			padding: var(--spacing-xs) var(--spacing-md);
			background-color: rgba(255, 255, 255, 0.8);
			backdrop-filter: blur(10px);
			-webkit-backdrop-filter: blur(10px);
		}
		.dark #tool-menu {
			background-color: rgba(29, 29, 31, 0.85);
		}
		body.manage #tool-menu {
			display: flex;
			gap: var(--spacing-sm);
			align-items: center;
		}
		#tab-head-container {
			display: flex;
			gap: var(--spacing-xs);
			align-items: center;
			overflow-x: auto;
			scrollbar-width: none;
			-ms-overflow-style: none;
		}
		#tab-head-container::-webkit-scrollbar {
			display: none;
		}
		#tab-plus,
		.tab-head {
			border-radius: var(--radius-md);
			padding: var(--spacing-xs) var(--spacing-sm);
			transition: background-color var(--transition-fast), transform var(--transition-fast), box-shadow var(--transition-medium);
			border: none;
			display: flex;
			align-items: center;
			cursor: pointer;
			height: 28px;
			user-select: none;
		}
		#tab-plus {
			background-color: var(--tab-inactive);
			color: var(--secondary);
			font-weight: 500;
			font-size: 16px;
			justify-content: center;
			min-width: 28px;
		}
		.tab-head:not(.active) {
			background-color: var(--tab-inactive);
			color: var(--secondary);
		}
		.tab-head.active {
			background-color: var(--accent);
			color: white;
			font-weight: 500;
			box-shadow: 0 3px 10px rgba(0, 113, 227, 0.3);
		}
		.dark .tab-head.active {
			box-shadow: 0 3px 10px rgba(41, 151, 255, 0.3);
		}
		#tab-plus:hover,
		.tab-head:not(.active):hover {
			background-color: var(--button-hover);
			transform: translateY(-1px);
		}
		.tab-head.active:hover {
			transform: translateY(-1px);
		}
		.tab-head.active:active, 
		#tab-plus:active,
		.tab-head:not(.active):active {
			transform: translateY(0);
		}
		body.manage {
			.card {
				padding-right: var(--spacing-md);
				position: relative;
				.card-extra {
					display: none;
				}
			}
			.card-close-button {
				position: absolute;
				right: var(--spacing-xs);
				top: 50%;
				transform: translateY(-50%);
				opacity: 0.7;
				transition: opacity var(--transition-fast);
				width: 22px;
				height: 22px;
				display: flex;
				align-items: center;
				justify-content: center;
				border-radius: 50%;
				background-color: var(--card-hover);
				
				&:hover {
					opacity: 1;
					background-color: var(--danger);
					color: white;
				}
			}
			.tab-head-close-button {
				margin-left: var(--spacing-xs);
				opacity: 0.7;
				transition: opacity var(--transition-fast), transform var(--transition-fast);
				width: 18px;
				height: 18px;
				display: flex;
				align-items: center;
				justify-content: center;
				border-radius: 50%;
				
				&:hover {
					opacity: 1;
					transform: scale(1.1);
					background-color: rgba(255, 255, 255, 0.3);
				}
			}
			.tab-head-close-button::after,
			.card-close-button::after {
				content: "×";
				font-size: 16px;
				line-height: 1;
				cursor: pointer;
			}
		}
		.button-control,
		.text-control {
			border-radius: var(--radius-md);
			padding: var(--spacing-xs) var(--spacing-sm);
			background-color: transparent;
			transition: background-color var(--transition-fast), transform var(--transition-fast);
			user-select: none;
			height: 28px;
			display: flex;
			align-items: center;
			cursor: pointer;
		}
		.text-control {
			padding-right: var(--spacing-md);
		}
		.tab-head span {
			outline: none;
			margin-right: var(--spacing-xs);
		}
		#settings-menu {
			border-left: 1px solid var(--border);
			padding: var(--spacing-md);
			min-width: 200px;
			background-color: var(--background);
			transition: border-color var(--transition-medium);
		}
		.emoji {
			font-family: 'Apple Color Emoji', 'Segoe UI Emoji', sans-serif;
			margin-right: 4px;
		}
		.text-control:hover,
		.button-control:hover {
			background-color: var(--button-hover);
			transform: translateY(-1px);
		}
		.text-control:active,
		.button-control:active {
			transform: translateY(0);
		}
		#trash-button.dragover {
			background-color: var(--danger);
			color: white;
			transform: scale(1.1);
		}
		.tab-content {
			overflow-y: auto;
			flex: 1;
			padding: var(--spacing-md);
			display: flex;
			flex-direction: column;
			gap: var(--spacing-sm);
			transition: all var(--transition-medium);
		}
		.tab-content:not(.active) {
			display: none;
		}
		.card.selected {
			background-color: var(--card-select);
			border-left: 3px solid var(--accent);
		}
		.card.selected:hover {
			background-color: var(--card-hover);
		}
		.card.selected[draggable=true] {
			cursor: grab;
		}
		.card {
			position: relative;
			border-radius: var(--radius-md);
			background-color: var(--background);
			box-shadow: var(--shadow);
			max-height: max(50%, 100px);
			box-sizing: border-box;
			overflow: hidden;
			display: flex;
			transition: transform var(--transition-fast), 
						box-shadow var(--transition-medium), 
						background-color var(--transition-fast),
						border-left var(--transition-fast);
			border-left: 3px solid transparent;
		}
		.card:hover {
			background-color: var(--card-hover);
			transform: translateY(-2px);
			box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08);
		}
		.dark .card:hover {
			box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
		}
		
        .card-checkbox {
            margin: var(--spacing-md);
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 4px;
            border: 1.5px solid var(--secondary);
            background-color: var(--background);
            position: relative;
            cursor: pointer;
            transition: all var(--transition-fast);
            
            &:checked {
                background-color: var(--accent);
                border-color: var(--accent);
                
                &::after {
                    content: "";
                    position: absolute;
                    top: 3px;
                    left: 6px;
                    width: 4px;
                    height: 8px;
                    border: solid white;
                    border-width: 0 2px 2px 0;
                    transform: rotate(45deg);
                }
            }
            
            &:hover {
                border-color: var(--accent);
            }
        }
		.card-wrapper {
			width: 100%;
			box-sizing: border-box;
			overflow-y: auto;
			padding: var(--spacing-md);
			flex: 1;
			.card-content {
				outline: none;
				width: 100%;
				padding-block: var(--spacing-xs);
				transition: all var(--transition-medium);
				* {
					pointer-events: none;
				}
			}
			.card-extra:empty {
				display: none;
			}
		}
		.card.text {
			.card-content {
				font-family: 'SF Mono', SFMono-Regular, ui-monospace, Menlo, Monaco, monospace;
				white-space: pre-wrap;
				word-break: break-all;
				font-size: 13px;
			}
		}
		.card.html {
			.card-content * {
				margin: 0 !important
			}
		}
		body:not(.manage) {
			.card.file .card-content:hover {
				color: var(--accent);
			}
		}
		.card.file {
			.card-content {
				font-family: 'SF Mono', SFMono-Regular, ui-monospace, Menlo, Monaco, monospace;
				white-space: nowrap;
				overflow-x: auto;
				font-size: 13px;
				display: flex;
				align-items: center;
				&.file::before,
				&.non-exist::before {
					content: "📄";
					margin-right: var(--spacing-sm);
					font-size: 16px;
				}
				&.directory::before {
					content: "📁";
					margin-right: var(--spacing-sm);
					font-size: 16px;
				}
				&.directory.open::before {
					content: "📂";
					margin-right: var(--spacing-sm);
					font-size: 16px;
				}
				&.non-exist {
					text-decoration: line-through;
					opacity: 0.7;
				}
				&::-webkit-scrollbar {
					height: 4px;
				}
			}
			.card-extra {
				font-family: 'SF Mono', SFMono-Regular, ui-monospace, Menlo, Monaco, monospace;
				white-space: nowrap;
				overflow-y: auto;
				margin-top: var(--spacing-sm);
				padding: var(--spacing-sm);
				border-radius: var(--radius-sm);
				border-top: 1px solid var(--border);
				max-height: 250px;
				background-color: rgba(0, 0, 0, 0.02);
				transition: border-color var(--transition-medium);
				.dark & {
					background-color: rgba(255, 255, 255, 0.05);
				}
				img {
					max-width: 100%;
					max-height: 100%;
					border-radius: var(--radius-sm);
					object-fit: contain;
				}
				.card:last-of-type {
					border-bottom: none;
				}
			}
		}
		#card-container {
			display: flex;
			flex: 1;
			overflow-y: auto;
		}
		.config-option {
			display: flex;
			align-items: center;
			padding: var(--spacing-xs) 0;
			cursor: pointer;
			transition: color var(--transition-fast);
			
			&:hover {
				color: var(--accent);
			}
		}
		select.config-option[size] {
			border-radius: var(--radius-sm);
			border: 1px solid var(--border);
			background-color: var(--background);
			color: var(--text);
			outline: none;
			padding: var(--spacing-xs);
			margin: var(--spacing-xs) 0 var(--spacing-md) 0;
			cursor: pointer;
			transition: all var(--transition-medium);
			
			&:focus {
				border-color: var(--accent);
			}
			
			option {
				padding: var(--spacing-xs);
			}
		}
		label {
			display: block;
			margin: var(--spacing-sm) 0 var(--spacing-xs) 0;
			font-weight: 500;
		}
		
     input[type="checkbox"] {
         appearance: none;
         width: 18px;
         height: 18px;
         border-radius: 4px;
         border: 1.5px solid var(--secondary);
         margin-right: var(--spacing-sm);
         position: relative;
         cursor: pointer;
         transition: all var(--transition-fast);
         background-color: var(--background);
         
         &:checked {
             background-color: var(--accent);
             border-color: var(--accent);
             
             &::after {
                 content: "";
                 position: absolute;
                 top: 3px;
                 left: 6px;
                 width: 4px;
                 height: 8px;
                 border: solid white;
                 border-width: 0 2px 2px 0;
                 transform: rotate(45deg);
             }
         }
         
         &:hover {
             border-color: var(--accent);
         }
         
         &:focus {
             outline: none;
             box-shadow: 0 0 0 2px rgba(0, 113, 227, 0.3);
         }
     }
     
     .dark input[type="checkbox"] {
         background-color: var(--background-dark);
     }
		/* Animations */
		@keyframes fadeIn {
			from { opacity: 0; }
			to { opacity: 1; }
		}
		@keyframes slideIn {
			from { transform: translateY(10px); opacity: 0; }
			to { transform: translateY(0); opacity: 1; }
		}
		.card {
			animation: slideIn var(--transition-medium) ease-out;
		}
		.tab-head {
			animation: fadeIn var(--transition-fast) ease-out;
		}
	</style>
	<style>
		.dark {
			--background: var(--background-dark);
			--text: var(--text-dark);
			--secondary: var(--secondary-dark);
			--border: var(--border-dark);
			--card-hover: var(--card-hover-dark);
			--card-select: var(--card-select-dark);
			--tab-inactive: var(--tab-inactive-dark);
			--button-hover: var(--button-hover-dark);
			--accent: var(--accent-dark);
			--danger: var(--danger-dark);
			--shadow: var(--shadow-dark);
		}
	</style>
</head>
<body>
	<nav id="tab-bar">
		<div id="tab-head-container">
			<div id="tab-plus">+</div>
		</div>
		<div style="display: flex; gap: var(--spacing-xs);">
			<div class="button-control emoji" id="trash-button" title="点击删除选中条目
或拖动到这里删除">🗑</div>
			<div class="button-control emoji" id="settings-trigger"
				onclick="document.querySelector('#settings-menu').hidden^=1" title="设置">⚙
			</div>
			<div class="button-control emoji" id="edit-toggle" title="编辑内容" onclick="toggleManage()">📝</div>
			<div class="button-control emoji" id="tool-refreshfile" title="刷新文件状态">🔄</div>
			<div class="button-control emoji" id="tool-readclipboard" title="添加剪贴板条目">➕</div>
        </div>
	</nav>
	<div id="tool-menu" hidden>
		<div class="text-control emoji" id="tool-clearformat">🧹 清除格式</div>
		<div class="text-control emoji" id="tool-cardjoin">🔗 合并</div>
	</div>
	<div style="display:flex;flex:1;overflow-y:auto;">
		<div id="card-container"></div>
		<div id="settings-menu" style="overflow-y:auto;" hidden>
			<label class="config-option"><input type="checkbox" id="config-richin" checked>拖入保留格式</label>
			<label class="config-option"><input type="checkbox" id="config-richout" checked>拖出保留格式</label>
			<label class="config-option"><input type="checkbox" id="config-copynotify">复制后提示消息</label>
			<label class="config-option"><input type="checkbox" id="config-droponjoin">合并后删除原卡片</label>
			<label class="config-option"><input type="checkbox" id="config-autopreview" checked>拖入文件自动预览</label>
			<label>单击效果</label>
			<select class="config-option" id="config-clickevent" size="2">
				<option value="none" selected>无</option>
				<option value="copy">复制</option>
			</select>
			<label>双击效果——文本</label>
			<select class="config-option" id="config-text-dblclick" size="3">
				<option value="none">无</option>
				<option value="copy">复制</option>
				<option value="edit" selected>编辑</option>
			</select>
			<label>双击效果——文件</label>
			<select class="config-option" id="config-file-dblclick" size="5">
				<option value="none">无</option>
				<option value="copy">复制</option>
				<option value="open">打开</option>
				<option value="preview" selected>预览</option>
				<option value="locate">定位</option>
			</select>
			<label class="config-option"><input type="checkbox" id="config-previewfallback" checked>预览失败时打开文件</label>
			<label>拖放效果</label>
			<select class="config-option" id="config-dropeffect" size="4">
				<option value="all" selected>自动</option>
				<option value="copy">复制</option>
				<option value="move">移动</option>
				<option value="link">链接</option>
			</select>
			<label>主题颜色</label>
			<select class="config-option" id="config-colorscheme" size="3" onchange="updateTheme()">
				<option value="light">亮</option>
				<option value="dark">暗</option>
				<option value="system" selected>系统</option>
			</select>
		</div>
	</div>
	<script>
		function createElement(tagName, property = {}) {
			let ele = document.createElement(tagName);
			for (let attribute in property) {
				if (attribute == "style") {
					for (let key in property.style) {
						ele.style[key] = property.style[key]
					}
				} else {
					if (attribute) ele[attribute] = property[attribute]
				}
			}
			return ele
		}
		function getDateString(date) {
			return `${date.getFullYear()}${date.getMonth() + 1}${date.getDate()}_${date.getHours()}${date.getMinutes()}${date.getSeconds()}`
		}
		function getRandomId(prefix) {
			let id = prefix + "-" + Math.random().toString(36).slice(2);
			if (document.getElementById(id)) return getRandomId(prefix);
			return id;
		}
		function getFullPathAsync(file) {
			let timestamp = +new Date();
			let { resolve, reject, promise } = Promise.withResolvers();
			let listener = function (e) {
				if (e.data.op == "customMessage" && e.data.action == "responseFullPath" && e.data.timestamp == timestamp) {
					chrome.webview.removeEventListener("message", listener);
					resolve(e.data.paths[0]);
				}
			}
			chrome.webview.addEventListener("message", listener);
			try {
				chrome.webview.postMessageWithAdditionalObjects({
					op: "customMessage", action: "requestFullPath", timestamp
				}, [file]);
			} catch (e) { reject(e); }
			return promise;
		}
		function getFileSystemHandlerAsync(path) {
			let timestamp = +new Date();
			let { resolve, reject, promise } = Promise.withResolvers();
			let listener = function (e) {
				if (e.data.op == "customMessage" && e.data.action == "responseFile" && e.data.timestamp == timestamp) {
					chrome.webview.removeEventListener("message", listener);
					resolve(e.additionalObjects[0]);
				}
			}
			chrome.webview.addEventListener("message", listener);
			chrome.webview.postMessage({
				op: "customMessage", action: "requestFile", timestamp, paths: [path]
			});
			return promise;
		}
		async function saveTempfileAsync(file) {
			let { promise, resolve, reject } = Promise.withResolvers();
			const reader = new FileReader();
			reader.onload = (event) => resolve(event.target.result);
			reader.onerror = (error) => reject(error);
			reader.readAsDataURL(file)
			let data = await promise;
			let { path } = await $quickerSp('保存临时文件', {
				data: data.split(",").pop(),
				ext: file.type.split("/").pop()
			});
			return path;
		}
		async function getFileInfoAsync(path) {
			let res = await $quickerSp('获取文件信息', { path });
			res.type = !res.exists ? "non-exist" : res.isDirectory ? "directory" : "file";
			return res;
		}
		function notify(message, type = "Info") {
			$quickerSp('提示消息', { type, message });
		}
		// Extend Array with fromAsync utility
		Array.fromAsync = async function(items, mapFn) {
			const results = [];
			for (const item of items) {
				results.push(await mapFn(item));
			}
			return results;
		};
	</script>
	<script>
		function createTab(name) {
			let id = "tab-" + Math.random().toString(36).slice(2);
			if (document.getElementById(id)) return createTab(name);
			let thContainer = document.querySelector('#tab-head-container');
			if (!name) name = "标签" + thContainer.childElementCount;
			let tbPlus = document.querySelector('#tab-plus');
			let tabHead = createElement('div', {
				id, className: 'tab-head',
				draggable: true,
				ondragstart: function (e) {
					e.dataTransfer.setData("text/plain", this.innerText);
					e.dataTransfer.setData("datatransfer/tab", id);
					e.dataTransfer.effectAllowed = "all";
					e.dataTransfer.setDragImage(new Image(), 0, 0);
				},
			});
			tbPlus.before(tabHead);
			tabHead.append(createElement('span', {
				className: 'tab-head-content',
				innerText: name,
				onblur: function (e) {
					if (this.innerText == "") this.innerText = "标签";
				},
				onkeydown: function (e) {
					if (e.key == "Enter") {
						e.preventDefault();
						this.blur();
					}
				}
			}));
			tabHead.append(createElement('span', {
				className: 'tab-head-close-button',
				onclick: (e) => {
					e.stopPropagation();
					tabHead.dispose();
				}
			}));
			let tabContent = createElement('div', { className: 'tab-content' });
			document.querySelector('#card-container').append(tabContent);
			tabHead.contentDiv = tabContent;
			tabContent.headDiv = tabHead;
			tabHead.ondragover = function (e) {
				e.preventDefault();
				e.dataTransfer.dropEffect = "move";
			};
			tabHead.ondrop = function (e) {
				e.preventDefault();
				let data;
				data = e.dataTransfer.getData("datatransfer/tab");
				if (data) {
					let targetTab = e.target.closest('.tab-head');
					let draggingElement = document.getElementById(data);
					let appendFunc = e.offsetX < targetTab.clientWidth / 2 ? "before" : "after";
					targetTab[appendFunc](draggingElement);
					draggingElement.activate();
					return
				}
			};
			tabHead.dispose = tabContent.dispose = function () {
				if (tabHead.classList.contains("active")) {
					if (tabHead.previousElementSibling) tabHead.previousElementSibling.activate();
					else if (tabHead.nextElementSibling != tbPlus) tabHead.nextElementSibling.activate();
				}
				// Add slide out animation before removal
				tabHead.style.transition = "all 0.3s";
				tabContent.style.transition = "all 0.3s";
				
				tabHead.style.transform = "translateY(-20px)";
				tabHead.style.opacity = "0";
				
				tabContent.style.transform = "translateY(20px)";
				tabContent.style.opacity = "0";
				
				setTimeout(() => {
					tabHead.remove();
					tabContent.remove();
					if (!document.querySelector('.tab-head.active')) createTab().activate();
				}, 300);
			};
			tabContent.activate = tabHead.activate = tabHead.onclick = function () {
				document.querySelectorAll('.tab-head.active').forEach(e => {
					if (e != tabHead) e.classList.remove('active')
				});
				document.querySelectorAll('.tab-content').forEach(e => {
					if (e != tabContent) {
						e.classList.remove('active');
						e.querySelectorAll('.card.selected').forEach(cd => cd.classList.remove("selected"));
					}
				});
				tabHead.classList.add('active');
				tabContent.classList.add('active');
			};
			tabHead.ondragenter = function (e) {
				let activeHead = document.querySelector('.tab-head.active')
				let activeContent = document.querySelector('.tab-content.active')
				if (activeHead != tabHead) {
					activeHead.classList.remove('active');
					tabHead.classList.add('active');
				}
				if (activeContent != tabContent) {
					activeContent.classList.remove('active');
					tabContent.classList.add('active');
				}
			}
			tabContent.ondrop = async function (e) {
				e.preventDefault();
				e.dataTransfer.dropEffect = "copy";
				targetCard = e.target.closest('.card');
				if (e.dataTransfer.types.includes("datatransfer/card") && e.dataTransfer.effectAllowed != "copy") {
					let elements = e.dataTransfer.getData("datatransfer/card").split("\n").map(x => document.getElementById(x));
					if (targetCard) {
						let appendFunc = e.offsetY < targetCard.clientHeight / 2 ? "before" : "after";
						targetCard[appendFunc](...elements);
					} else {
						tabContent.append(...elements);
					}
				} else {
					if (targetCard) {
						let appendFunc = e.offsetY < targetCard.clientHeight / 2 ? "before" : "after";
						targetCard[appendFunc](...await createCardFromDataTransfer(e.dataTransfer));
					} else {
						tabContent.append(...await createCardFromDataTransfer(e.dataTransfer));
					}
				}
			};
			tabContent.ondragover = function (e) {
				e.preventDefault();
				if (e.dataTransfer.types.includes("datatransfer/card")) {
					e.dataTransfer.dropEffect = "all";
				} else {
					e.dataTransfer.dropEffect = "copy";
				}
			};
			tabContent.onclick = function (e) {
				if (e.target == e.currentTarget) document.querySelectorAll('.card.selected').forEach(ele => ele.selected = false);
			};
			return tabHead;
		}
	</script>
	<script>
		let editing = false;
		function toggleManage() {
			editing = !editing;
			document.body.classList.toggle('manage', editing);
			for (let card of document.querySelectorAll('.card')) {
				card.editable = editing;
			}
			for (let ele of document.querySelectorAll('.tab-head-content')) {
				if (!editing) {
					ele.contentEditable = false;
				} else {
					ele.contentEditable = "plaintext-only";
				}
			}
		}
		function getSelectedCardData() {
			let selectedCards = Array.from(document.querySelector('.tab-content.active').querySelectorAll('.card.selected'));
			let data = {
				"datatransfer/card": selectedCards.map(ele => ele.id).join("\n"),
			};
			if (selectedCards.some(x => x.type == "file")) {
				data["Files"] = selectedCards.filter(ele => ele.type == "file").map(ele => ele.contentDiv.innerText);
			}
			data["text/plain"] = selectedCards.map(ele => ele.contentDiv.innerText).join("\n");
			if (config.richout) {
				data["text/html"] = selectedCards.map(ele => ele.contentDiv.innerHTML).join("<br>");
			}
			return data;
		}
		function getSelectedCardJoin() {
			let selectedCards = Array.from(document.querySelector('.tab-content.active').querySelectorAll('.card.selected'));
			if (selectedCards.some(x => x.type == "html")) {
				return createHTMLCard(selectedCards.map(x => x.contentDiv.innerHTML).join("<br>"));
			} else {
				return createTextCard(selectedCards.map(x => x.contentDiv.innerText).join("\n"));
			}
		}
		function selectCard(card, dropOthers = false) {
			if (dropOthers) document.querySelectorAll('.card.selected').forEach(ele => ele.selected = false);
			card.selected = true;
		}
		function onCardDragStart(e) {
			selectCard(e.currentTarget, document.querySelectorAll('.card.selected').length <= 1 && !e.currentTarget.selected && !e.ctrlKey);
			e.preventDefault();
			let effect = e.ctrlKey ? "copy" : config.dropeffect;
			chrome.webview.postMessage({
				op: "customMessage", action: "doDragDrop",
				effect, data: getSelectedCardData()
			});
		}
		async function onCardClick(e) {
			if (editing) return;
			e.stopPropagation();
			selectCard(e.currentTarget, !e.ctrlKey);
			if (config.clickevent == "copy") {
				clipboardWrite("copy");
			}
		}
		async function onCardContextMenu(e) {
			if (editing) return;
			e.preventDefault();
			e.stopPropagation();
			let activeCard = e.currentTarget;
			selectCard(activeCard, document.querySelectorAll('.card.selected').length <= 1 && !activeCard.selected && !e.ctrlKey);
			let selectedCards = Array.from(document.querySelector('.tab-content.active').querySelectorAll('.card.selected'));
			let types = cardTypes.filter(x => selectedCards.some(ele => ele.type == x));
			let menuData = [
				"[fa:Regular_Copy]复制|复制",
				"[fa:Regular_Trash]删除|删除",
			];
			let paths = selectedCards.filter(x => x.type == "file").map(x => x.contentDiv.innerText);
			if (selectedCards.length == 1) {
				if (activeCard.type == "html") {
					menuData.push("[fa:Solid_Edit]编辑HTML源码|编辑HTML源码");
				}
				if (activeCard.type == "file") {
					let contentDiv = activeCard.contentDiv
					let { exists, isDirectory } = await getFileInfoAsync(contentDiv.innerText);
					if (exists) {
						menuData.push("[fa:Solid_PaperPlane]用默认打开方式打开|打开文件");
						menuData.push("[fa:Regular_FolderOpen]在资源管理器中定位|在资源管理器中定位文件");
					}
					if (isDirectory) {
						if (contentDiv.classList.contains("open"))
							menuData.push("[fa:Regular_FolderTree]收起|收起文件夹");
						else
							menuData.push("[fa:Regular_FolderTree]列出文件|展开文件夹");
					}
				}
			}
			menuData.push("[fa:Regular_ArrowCircleRight]转换为");
			if (types.some(x => x != "text")) {
				menuData.push("  [fa:Regular_Text]纯文本|转换为纯文本");
			}
			if (types.some(x => x != "html")) {
				menuData.push("  [fa:Regular_Globe]HTML|转换为HTML");
			}
			if (types.some(x => x != "file")) {
				menuData.push("  [fa:Regular_File]文件|转换为文件");
			}
			if (selectedCards.length > 1) {
				menuData.push("[fa:Regular_Archive]合并|合并");
			}
			menuData.push("[fa:Regular_Text]将文本另存为|保存文本");
			if (types.includes("file")) {
				menuData.push("[fa:Regular_FileAlt]文件操作");
				menuData.push("  [fa:Brands_Windows]资源管理器菜单|资源管理器菜单");
				menuData.push("  [fa:Regular_Copy]将所选文件(夹)复制到|文件复制到");
				menuData.push("  [fa:Regular_FolderOpen]将所选文件(夹)移动到|文件移动到");
			}
			let { action } = await $quickerSp('右键菜单', { menuData });
			if (action == "复制") {
				clipboardWrite("copy");
			} else if (action == "转换为纯文本") {
				selectedCards.forEach(ele => ele?.assign?.("type", "text"));
			} else if (action == "转换为文件") {
				selectedCards.forEach(ele => ele?.assign?.("type", "file"));
			} else if (action == "转换为HTML") {
				selectedCards.forEach(ele => ele?.assign?.("type", "html"));
			} else if (action == "删除") {
				// Add animation before removal
				for (let card of selectedCards) {
					card.style.transition = "all 0.3s";
					card.style.transform = "translateX(50px)";
					card.style.opacity = "0";
				}
				// Remove after animation completes
				setTimeout(() => {
					selectedCards.forEach(ele => ele?.remove());
				}, 300);
			} else if (action == "编辑") {
				selectedCards.forEach(ele => ele?.editContent());
			} else if (action == "编辑HTML源码") {
				selectedCards.forEach(ele => ele?.editSource());
			} else if (action == "展开文件夹") {
				selectedCards.forEach(ele => ele?.assign?.("open", true));
			} else if (action == "收起文件夹") {
				selectedCards.forEach(ele => ele?.assign?.("open", false));
			} else if (action == "打开文件") {
				$quickerSp('运行或打开', { path: paths });
			} else if (action == "在资源管理器中定位文件") {
				$quickerSp('在资源管理器中定位文件', { path: paths });
			} else if (action == "资源管理器菜单") {
				$quickerSp('资源管理器菜单', { paths });
			} else if (action == "文件复制到") {
				$quickerSp('文件和目录操作', { paths, action: "copy" });
			} else if (action == "文件移动到") {
				$quickerSp('文件和目录操作', { paths, action: "move" });
			} else if (action == "保存文本") {
				$quickerSp('将文本另存为', { text: selectedCards.map(x => x.contentDiv.innerText).join("\n") });
			} else if (action == "合并") {
				const newCard = await getSelectedCardJoin();
				activeCard.before(newCard);
				
				// Add slide-in animation for new card
				newCard.style.transform = "translateY(20px)";
				newCard.style.opacity = "0";
				setTimeout(() => {
					newCard.style.transform = "translateY(0)";
					newCard.style.opacity = "1";
				}, 10);
				
				if (config.droponjoin) {
					// Add slide-out animation before removal
					for (let card of selectedCards) {
						card.style.transition = "all 0.3s";
						card.style.transform = "translateY(20px)";
						card.style.opacity = "0";
					}
					// Remove after animation completes
					setTimeout(() => {
						selectedCards.forEach(ele => ele.remove());
					}, 300);
				}
			}
		}
		async function clipboardWrite(effect = "all") {
			await chrome.webview.postMessage({
				op: "customMessage", action: "doCopy",
				effect, data: getSelectedCardData()
			});
			if (config.copynotify) {
				notify("已复制到剪贴板", "Success");
			}
		}
		async function createDirectoryDiv(path) {
			let div = createElement('div', { className: 'items', innerText: path });
			path = path.replace(/\\+$/g, "");
			let handle = await getFileSystemHandlerAsync(path)
			div.replaceChildren(...await Array.fromAsync(handle.values(), h => createFileCard(`${path}\\${h.name}`)))
			return div;
		}
		const cardTypes = ["html", "file", "text", "image"];
		function createCardBase() {
			let card = createElement('div', {
				id: getRandomId("card"), className: 'card', draggable: true,
				ondragstart: onCardDragStart, onclick: onCardClick, oncontextmenu: onCardContextMenu
			});
			
			let checkbox = createElement('input', {
				type: 'checkbox', className: 'card-checkbox',
				onclick: (e) => e.stopPropagation(),
				onchange: async function (e) {
					card.classList.toggle('selected', this.checked)
					if (config.clickevent == "copy") {
						clipboardWrite("copy");
					}
				}
			});
			
			card.append(checkbox);
			let cardWrapper = createElement('div', { className: 'card-wrapper' });
			let cardContent = createElement('div', { className: 'card-content' });
			let cardExtra = createElement('div', { className: 'card-extra' });
			card.append(cardWrapper);
			cardWrapper.append(cardContent);
			cardWrapper.append(cardExtra);
			card.append(createElement('div', {
				className: 'card-close-button',
				onclick: function (e) {
					e.stopPropagation();
					
					// Add slide-out animation before removal
					card.style.transition = "all 0.3s";
					card.style.transform = "translateY(20px)";
					card.style.opacity = "0";
					
					// Remove after animation completes
					setTimeout(() => {
						card.remove();
					}, 300);
				}
			}));
			
			Object.defineProperty(card, "selected", {
				get: function () { return checkbox.checked; },
				set: function (value) { 
					let v = !!value; 
					checkbox.checked = v; 
					card.classList.toggle("selected", v);
					
					// Add subtle animation when selected
					if (v) {
						card.animate([
							{ transform: 'scale(1)' },
							{ transform: 'scale(1.02)' },
							{ transform: 'scale(1)' }
						], {
							duration: 300,
							easing: 'ease-in-out'
						});
					}
				}
			});
			
			Object.defineProperty(card, "editable", {
				get: function () { return card.draggable },
				set: function (value) {
					let type = card.type;
					if (value) {
						card.draggable = false;
						cardContent.contentEditable = type == "html" ? true : 'plaintext-only';
						
						// Add edit mode styling
						cardContent.style.boxShadow = "inset 0 0 0 2px var(--accent)";
						cardContent.style.padding = "var(--spacing-sm)";
						cardContent.style.borderRadius = "var(--radius-sm)";
						
						// Focus on the content
						setTimeout(() => {
							cardContent.focus();
							// Place cursor at end
							const range = document.createRange();
							range.selectNodeContents(cardContent);
							range.collapse(false);
							const selection = window.getSelection();
							selection.removeAllRanges();
							selection.addRange(range);
						}, 10);
					} else {
						card.draggable = true;
						cardContent.contentEditable = false;
						
						// Remove edit mode styling
						cardContent.style.boxShadow = "";
						cardContent.style.padding = "";
					}
				},
				configurable: true
			});
			
			Object.defineProperty(card, "type", {
				get: function () { return cardTypes.find(x => [...card.classList].includes(x)); },
				set: function (new_type) {
					let old_type = card.type;
					card.classList.remove(...cardTypes);
					cardExtra.replaceChildren();
					
					if (new_type == "html") {
						card.classList.add("html");
					}
					if (new_type == "file") {
						card.classList.add("file");
						cardContent.textContent = cardContent.innerText;
					}
					if (new_type == "text") {
						card.classList.add("text");
						if (old_type == "html") {
							cardContent.textContent = cardContent.innerText.replace(/\r/g, "").replace(/\n\n+/g, "\n\n");
						} else {
							cardContent.textContent = cardContent.innerText;
						}
					}
					
					// Add animation when changing type
					card.animate([
						{ opacity: 0.7 },
						{ opacity: 1 }
					], {
						duration: 300,
						easing: 'ease-in-out'
					});
					
					card.updateInfo();
				}
			});
			
			Object.defineProperty(card, "open", {
				get: function () { return cardContent.classList.contains("open"); },
				set: async function (value) {
					if (editing) return;
					
					const wasOpen = cardContent.classList.contains("open");
					cardContent.classList.toggle("open", value);
					
					if (!value) {
						// Add animation for closing
						if (wasOpen) {
							cardExtra.style.transition = "all 0.3s";
							cardExtra.style.maxHeight = "0";
							cardExtra.style.opacity = "0";
							
							// Wait for animation then clear
							setTimeout(() => {
								cardExtra.replaceChildren();
								cardExtra.style = "";
							}, 300);
						}
						return;
					}
					
					if (card.type != "file") return;
					let path = cardContent.innerText;
					let { exists, isDirectory, mime } = await getFileInfoAsync(path);
					if (!exists) return;
					
					// Start with zero height for animation
					if (!wasOpen) {
						cardExtra.style.maxHeight = "0";
						cardExtra.style.opacity = "0";
						cardExtra.style.transition = "all 0.3s";
					}
					
					if (isDirectory) {
						let div = await createDirectoryDiv(path);
						cardExtra.replaceChildren(div);
					} else {
						let file = await getFileSystemHandlerAsync(path);
						file = await file.getFile();
						if (file == null) return;
						if (file.type.startsWith("image/")) {
							let img = createElement('img', { src: URL.createObjectURL(file) });
							img.ondblclick = function (e) {
								window.open(this.src, "_blank", `popup=yes,width=${window.innerWidth},height=${window.innerHeight},top=${window.screenY},left=${Math.max(window.screenX - window.innerWidth - 20, 0)}`);
							}
							cardExtra.replaceChildren(img);
						} else {
							throw new Error("Unsupported file type");
						}
					}
					
					// Animate opening
					if (!wasOpen) {
						setTimeout(() => {
							cardExtra.style.maxHeight = "250px";
							cardExtra.style.opacity = "1";
						}, 10);
					}
				},
				configurable: true
			});
			
			card.toggleExtra = async function (state) {
				if (editing) return;
				
				const wasOpen = cardContent.classList.contains("open");
				state = cardContent.classList.toggle("open", state);
				
				if (!state) {
					// Add animation for closing
					if (wasOpen) {
						cardExtra.style.transition = "all 0.3s";
						cardExtra.style.maxHeight = "0";
						cardExtra.style.opacity = "0";
						
						// Wait for animation then clear
						setTimeout(() => {
							cardExtra.replaceChildren();
							cardExtra.style = "";
						}, 300);
					}
					return;
				}
				
				if (card.type != "file") return;
				let path = cardContent.innerText;
				let { exists, isDirectory, mime } = await getFileInfoAsync(path);
				if (!exists) return;
				
				// Start with zero height for animation
				if (!wasOpen) {
					cardExtra.style.maxHeight = "0";
					cardExtra.style.opacity = "0";
					cardExtra.style.transition = "all 0.3s";
				}
				
				if (isDirectory) {
					let div = await createDirectoryDiv(path);
					cardExtra.replaceChildren(div);
				} else {
					let file = await getFileSystemHandlerAsync(path);
					file = await file.getFile();
					if (file == null) return;
					if (file.type.startsWith("image/")) {
						let img = createElement('img', { src: URL.createObjectURL(file) });
						img.ondblclick = function (e) {
							window.open(this.src, "_blank", `popup=yes,width=${window.innerWidth},height=${window.innerHeight},top=${window.screenY},left=${Math.max(window.screenX - window.innerWidth - 20, 0)}`);
						}
						cardExtra.replaceChildren(img);
					} else {
						cardContent.classList.toggle("open", false);
						throw new Error("Unsupported file type");
					}
				}
				
				// Animate opening
				if (!wasOpen) {
					setTimeout(() => {
						cardExtra.style.maxHeight = "250px";
						cardExtra.style.opacity = "1";
					}, 10);
				}
			};
			
			cardContent.ondblclick = async function () {
				if (editing) return;
				let type = card.type;
				if (type == "file") {
					let path = cardContent.innerText
					if (config.filedblclick == "copy") {
						clipboardWrite("copy");
					} else if (config.filedblclick == "locate") {
						$quickerSp('在资源管理器中定位文件', { path });
					} else if (config.filedblclick == "preview") {
						card.toggleExtra().catch(e => {
							if (config.previewfallback)
								$quickerSp('运行或打开', { path });
						})
					} else if (config.filedblclick == "open") {
						$quickerSp('运行或打开', { path });
					}
				} else {
					if (config.textdblclick == "copy") {
						clipboardWrite("copy");
					} else if (config.textdblclick == "edit") {
						if (type == "html") card.editContent();
						if (type == "text") card.editText();
					}
				}
			}
			
			cardContent.onblur = function (e) {
				let type = card.type;
				if (type == "file") {
					card.updateInfo();
				} else {
					if (cardContent.innerText.trim() == "") {
						// Add slide-out animation before removal
						card.style.transition = "all 0.3s";
						card.style.transform = "translateY(20px)";
						card.style.opacity = "0";
						
						// Remove after animation completes
						setTimeout(() => {
							card.remove();
						}, 300);
					}
				}
				
				// Remove edit mode styling
				cardContent.style.boxShadow = "";
				cardContent.style.padding = "";
			}
			
			card.updateInfo = async function () {
				if (card.type == "file") {
					let { type } = await getFileInfoAsync(cardContent.innerText);
					cardContent.classList.remove("file", "directory", "non-exist");
					cardContent.classList.add(type);
					if (type == "directory" && cardContent.classList.contains("open")) {
						let div = await createDirectoryDiv(cardContent.innerText)
						cardExtra.replaceChildren(div)
					} else {
						cardContent.classList.remove("open");
						cardExtra.replaceChildren();
					}
				} else {
					cardContent.classList.remove("file", "directory", "non-exist", "open");
				}
			}
			
			card.editText = function () {
				let win = window.open("about:blank", "_blank", `popup=yes,width=${window.innerWidth},height=${window.innerHeight},top=${window.screenY},left=${Math.max(window.screenX - window.innerWidth - 20, 0)}`);
				
				win.document.head.innerHTML = `
					<style>
						body {
							margin: 0;
							padding: 20px;
							font-family: 'SF Mono', SFMono-Regular, ui-monospace, Menlo, Monaco, monospace;
							font-size: 14px;
							line-height: 1.5;
							white-space: pre-wrap;
							word-break: break-all;
							height: 100vh;
							box-sizing: border-box;
						}
						
						body:focus {
							outline: none;
						}
						
						/* For dark mode */
						@media (prefers-color-scheme: dark) {
							body.system {
								background-color: #1d1d1f;
								color: #f5f5f7;
							}
						}
					</style>
				`;
				
				if (document.documentElement.classList.contains("dark")) {
					win.document.body.style.background = "#1d1d1f";
					win.document.body.style.color = "#f5f5f7";
				} else if (config.colorscheme === "system") {
					win.document.body.classList.add("system");
				}
				
				win.document.body.textContent = cardContent.innerText;
				win.document.body.contentEditable = "plaintext-only";
				
				win.document.body.addEventListener("keydown", function(e) {
					if (e.key === "Escape") {
						win.close();
					}
				});
				
				win.onunload = function (e) {
					cardContent.innerHTML = win.document.body.innerText;
				}
			}
			
			card.editContent = function () {
				let win = window.open("about:blank", "_blank", `popup=yes,width=${window.innerWidth},height=${window.innerHeight},top=${window.screenY},left=${Math.max(window.screenX - window.innerWidth - 20, 0)}`);
				
				win.document.head.innerHTML = `
					<style>
						body {
							margin: 0;
							padding: 20px;
							font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
							font-size: 14px;
							line-height: 1.5;
							height: 100vh;
							box-sizing: border-box;
						}
						
						body:focus {
							outline: none;
						}
						
						/* For dark mode */
						@media (prefers-color-scheme: dark) {
							body.system {
								background-color: #1d1d1f;
								color: #f5f5f7;
							}
						}
					</style>
				`;
				
				if (document.documentElement.classList.contains("dark")) {
					win.document.body.style.background = "#1d1d1f";
					win.document.body.style.color = "#f5f5f7";
				} else if (config.colorscheme === "system") {
					win.document.body.classList.add("system");
				}
				
				win.document.body.innerHTML = cardContent.innerHTML;
				win.document.body.contentEditable = true;
				
				win.document.body.addEventListener("keydown", function(e) {
					if (e.key === "Escape") {
						win.close();
					}
				});
				
				win.onunload = function (e) {
					cardContent.innerHTML = win.document.body.innerHTML;
				}
			}
			
			card.editSource = function () {
				let win = window.open("about:blank", "_blank", `popup=yes,width=${window.innerWidth},height=${window.innerHeight},top=${window.screenY},left=${Math.max(window.screenX - window.innerWidth - 20, 0)}`);
				
				win.document.head.innerHTML = `
					<style>
						body {
							margin: 0;
							padding: ID;
							font-family: 'SF Mono', SFMono-Regular, ui-monospace, Menlo, Monaco, monospace;
							font-size: 14px;
							line-height: 1.5;
							white-space: pre-wrap;
							word-break: break-all;
							height: 100vh;
							box-sizing: border-box;
						}
						
						body:focus {
							outline: none;
						}
						
						/* For dark mode */
						@media (prefers-color-scheme: dark) {
							body.system {
								background-color: #1d1d1f;
								color: #f5f5f7;
							}
						}
					</style>
				`;
				
				if (document.documentElement.classList.contains("dark")) {
					win.document.body.style.background = "#1d1d1f";
					win.document.body.style.color = "#f5f5f7";
				} else if (config.colorscheme === "system") {
					win.document.body.classList.add("system");
				}
				
				win.document.body.textContent = cardContent.innerHTML;
				win.document.body.contentEditable = "plaintext-only";
				
				win.document.body.addEventListener("keydown", function(e) {
					if (e.key === "Escape") {
						win.close();
					}
				});
				
				win.onunload = function (e) {
					cardContent.innerHTML = win.document.body.innerText;
				}
			}
			
			card.assign = function (property, value) {
				card[property] = value;
			}
			
			card.contentDiv = cardContent;
			return { card, cardContent };
		}
		async function createFileCard(path, { open } = {}) {
			if (path instanceof File) path = await getFullPathAsync(path);
			if (!path) return;
			let { card, cardContent } = createCardBase();
			card.classList.add("file");
			let { type } = await getFileInfoAsync(path);
			cardContent.classList.add(type);
			cardContent.innerText = path;
			if (open) card.toggleExtra(true).catch(e => { });
			
			// Add entry animation
			card.style.transform = "translateY(20px)";
			card.style.opacity = "0";
			setTimeout(() => {
				card.style.transform = "translateY(0)";
				card.style.opacity = "1";
			}, 10);
			
			return card;
		}
		function createHTMLCard(html) {
			let { card, cardContent } = createCardBase();
			card.classList.add("html");
			cardContent.innerHTML = html;
			
			// Add entry animation
			card.style.transform = "translateY(20px)";
			card.style.opacity = "0";
			setTimeout(() => {
				card.style.transform = "translateY(0)";
				card.style.opacity = "1";
			}, 10);
			
			return card;
		}
		function createTextCard(text) {
			if (!text) text = "新卡片";
			let { card, cardContent } = createCardBase();
			card.classList.add("text");
			cardContent.textContent = text;
			
			// Add entry animation
			card.style.transform = "translateY(20px)";
			card.style.opacity = "0";
			setTimeout(() => {
				card.style.transform = "translateY(0)";
				card.style.opacity = "1";
			}, 10);
			
			return card;
		}
		async function createCard(type, data, args) {
			if (type == "html") return createHTMLCard(data);
			if (type == "file") return createFileCard(data, args);
			return createTextCard(data);
		}
		async function createCardFromDataTransfer(dataTransfer) {
			let data;
			if (dataTransfer.types.includes("Files")) {
				return Array.fromAsync(
					dataTransfer.files, async (file) =>
					getFullPathAsync(file)
						.catch(e => saveTempfileAsync(file))
						.then(path => createFileCard(path, { open: config.autopreview }))
				);
			}
			if (config.richin) {
				data = dataTransfer.getData("text/html")
					.replace(/^<html>\s*/m, "").replace(/\s*<\/html>$/m, "")
					.replace(/^<body>\s*/m, "").replace(/\s*<\/body>$/m, "")
					.replace(new RegExp("<\!--StartFragment-->", "g"), "").replace(new RegExp("<\!--EndFragment-->", "g"), "");
				if (data != "") return [createHTMLCard(data)];
			}
			data = dataTransfer.getData("text/plain");
			return [createTextCard(data)];
		}
		document.querySelector('#tool-clearformat').onclick = (e) => {
			document.querySelectorAll('.card.selected').forEach(ele => ele.type = "text");
		};
		
		document.querySelector('#tool-cardjoin').onclick = async function (e) {
			let activeCard = document.querySelector('.tab-content.active').querySelector('.card.selected');
			if (!activeCard) return;
			
			let card = await getSelectedCardJoin();
			activeCard.before(card);
			card.editable = editing;
			
			// Add slide-in animation for new card
			card.style.transform = "translateY(20px)";
			card.style.opacity = "0";
			setTimeout(() => {
				card.style.transform = "translateY(0)";
				card.style.opacity = "1";
			}, 10);
			
			if (config.droponjoin) {
				let selectedCards = document.querySelector('.tab-content.active').querySelectorAll('.card.selected');
				// Add slide-out animation before removal
				for (let c of selectedCards) {
					c.style.transition = "all 0.3s";
					c.style.transform = "translateY(20px)";
					c.style.opacity = "0";
				}
				// Remove after animation completes
				setTimeout(() => {
					selectedCards.forEach(ele => ele.remove());
				}, 300);
			}
		};
		
		document.querySelector('#tool-readclipboard').onclick = () => {
			$quickerSp('添加剪贴板条目').catch(e => notify('剪贴板中没有内容', "Error"));
		};
		
		document.querySelector("#tool-refreshfile").onclick = async function (e) {
			// Add refresh animation
			const refreshButton = document.querySelector("#tool-refreshfile");
			refreshButton.style.transition = "transform 0.5s";
			refreshButton.style.transform = "rotate(360deg)";
			
			setTimeout(() => {
				refreshButton.style.transition = "none";
				refreshButton.style.transform = "rotate(0deg)";
			}, 500);
			
			let cardContents = document.querySelector('.tab-content.active').querySelectorAll('.card.selected.file>.card-wrapper>.card-content');
			if (cardContents.length == 0)
				cardContents = document.querySelectorAll('.card.file .card-content')
			for (let content of cardContents) {
				let card = content.closest('.card');
				let { type } = await getFileInfoAsync(content.innerText);
				content.classList.remove("file", "directory", "non-exist");
				content.classList.add(type);
			}
		};
		let tbPlus = document.querySelector('#tab-plus');
		let trashButton = document.querySelector("#trash-button");
		trashButton.onclick = function (e) {
			let selectedCards = document.querySelector(".tab-content.active").querySelectorAll('.card.selected');
			if (selectedCards.length != 0) {
				// Add slide-out animation before removal
				for (let card of selectedCards) {
					card.style.transition = "all 0.3s";
					card.style.transform = "translateY(20px)";
					card.style.opacity = "0";
				}
				// Remove after animation completes
				setTimeout(() => {
					selectedCards.forEach(ele => ele.remove());
				}, 300);
			}
		};
		
		trashButton.ondrop = function (e) {
			e.preventDefault();
			trashButton.classList.remove("dragover");
			let data;
			data = e.dataTransfer.getData("datatransfer/card");
			if (data) {
				for (let id of data.split("\n")) {
					let card = document.getElementById(id);
					// Add slide-out animation before removal
					card.style.transition = "all 0.3s";
					card.style.transform = "translateX(50px)";
					card.style.opacity = "0";
					// Remove after animation completes
					setTimeout(() => {
						card.remove();
					}, 300);
				}
				return
			}
			data = e.dataTransfer.getData("datatransfer/tab");
			if (data) {
				for (let id of data.split("\n")) {
					document.getElementById(id).dispose();
				}
				return
			}
		};
		
		trashButton.ondragover = function (e) {
			e.preventDefault();
			trashButton.classList.add("dragover");
			e.dataTransfer.dropEffect = "move";
		};
		
		trashButton.ondragleave = function (e) {
			trashButton.classList.remove("dragover");
		};
		
		tbPlus.onclick = e => {
			createTab().activate();
		};
		
		tbPlus.ondragover = function (e) {
			e.preventDefault();
			e.dataTransfer.dropEffect = "All";
		};
		
		tbPlus.ondrop = async function (e) {
			e.preventDefault();
			let tab = createTab();
			tab.contentDiv.append(...await createCardFromDataTransfer(e.dataTransfer));
			tab.activate();
		}
		
		document.oncontextmenu = function (e) {
			e.preventDefault();
		};
	</script>
	<script>
		const config = {
			get richin() { return document.querySelector('#config-richin').checked },
			set richin(value) { document.querySelector('#config-richin').checked = value },
			get richout() { return document.querySelector('#config-richout').checked },
			set richout(value) { document.querySelector('#config-richout').checked = value },
			get copynotify() { return document.querySelector('#config-copynotify').checked },
			set copynotify(value) { document.querySelector('#config-copynotify').checked = value },
			get clickevent() { return document.querySelector('#config-clickevent').value },
			set clickevent(value) { document.querySelector('#config-clickevent').value = value },
			get textdblclick() { return document.querySelector('#config-text-dblclick').value },
			set textdblclick(value) { document.querySelector('#config-text-dblclick').value = value },
			get filedblclick() { return document.querySelector('#config-file-dblclick').value },
			set filedblclick(value) { document.querySelector('#config-file-dblclick').value = value },
			get dropeffect() { return document.querySelector('#config-dropeffect').value },
			set dropeffect(value) { document.querySelector('#config-dropeffect').value = value },
			get droponjoin() { return document.querySelector('#config-droponjoin').checked },
			set droponjoin(value) { document.querySelector('#config-droponjoin').checked = value },
			get previewfallback() { return document.querySelector('#config-previewfallback').checked },
			set previewfallback(value) { document.querySelector('#config-previewfallback').checked = value },
			get autopreview() { return document.querySelector('#config-autopreview').checked },
			set autopreview(value) { document.querySelector('#config-autopreview').checked = value },
			get colorscheme() { return document.querySelector('#config-colorscheme').value },
			set colorscheme(value) { document.querySelector('#config-colorscheme').value = value },
		}
		
		function saveData() {
			let metadata = { ...config };
			let tabHeaders = Array.from(document.querySelectorAll('.tab-head'))
			metadata.activeTabN = tabHeaders.indexOf(document.querySelector('.tab-head.active'));
			let data = tabHeaders.map(tc => {
				let name = tc.innerText
				let cards = Array.from(tc.contentDiv.querySelectorAll('&>.card')).map(card => {
					let type = card.type;
					let content;
					if (type == "html") {
						content = card.contentDiv.innerHTML;
					} else {
						content = card.contentDiv.innerText;
					}
					let args = {};
					if (type == "file") {
						args.open = card.contentDiv.classList.contains("open");
					}
					return { type, content, args };
				})
				return { name, cards };
			});
			return $quickerSp("保存数据", { data: JSON.stringify({ metadata, data }) });
		}
		
		window.onkeydown = (e) => {
			if (e.ctrlKey && e.key == "s") {
				e.preventDefault();
				saveData().then(() => {
					notify("已保存", "Success");
					
					// Add save animation
					const flash = document.createElement('div');
					flash.style.position = "fixed";
					flash.style.top = "0";
					flash.style.left = "0";
					flash.style.right = "0";
					flash.style.bottom = "0";
					flash.style.backgroundColor = "rgba(255, 255, 255, 0.2)";
					flash.style.pointerEvents = "none";
					flash.style.zIndex = "9999";
					flash.style.animation = "flash 0.5s ease-out forwards";
					
					document.body.appendChild(flash);
					
					// Add keyframes for flash animation
					const style = document.createElement('style');
					style.textContent = `
						@keyframes flash {
							0% { opacity: 1; }
							100% { opacity: 0; }
						}
					`;
					document.head.appendChild(style);
					
					setTimeout(() => {
						flash.remove();
						style.remove();
					}, 500);
				});
			}
			
			if (e.ctrlKey && e.key == "e") {
				e.preventDefault();
				chrome.webview.postMessage({
					op: "customMessage", action: "moveWindowToCursor"
				});
			}
			
			if (!editing && e.ctrlKey && e.key == "a") {
				e.preventDefault();
				document.querySelector('.tab-content.active').querySelectorAll('.card').forEach(e => e.classList.add("selected"));
			}
			
			if (!editing && e.key == "Delete") {
				const selectedCards = document.querySelector('.tab-content.active').querySelectorAll('.card.selected');
				// Add slide-out animation before removal
				for (let card of selectedCards) {
					card.style.transition = "all 0.3s";
					card.style.transform = "translateX(50px)";
					card.style.opacity = "0";
				}
				// Remove after animation completes
				setTimeout(() => {
					selectedCards.forEach(e => e.remove());
				}, 300);
			}
			
			if (!editing && e.ctrlKey && e.key == "x") {
				e.preventDefault();
				clipboardWrite("move");
				const selectedCards = document.querySelector('.tab-content.active').querySelectorAll('.card.selected');
				// Add slide-out animation before removal
				for (let card of selectedCards) {
					card.style.transition = "all 0.3s";
					card.style.transform = "translateX(50px)";
					card.style.opacity = "0";
				}
				// Remove after animation completes
				setTimeout(() => {
					selectedCards.forEach(e => e.remove());
				}, 300);
			}
			
			if (!editing && e.ctrlKey && e.key == "c") {
				e.preventDefault();
				clipboardWrite('copy');
				
				// Add copy animation
				const selectedCards = document.querySelector('.tab-content.active').querySelectorAll('.card.selected');
				for (let card of selectedCards) {
					card.animate([
						{ boxShadow: '0 0 0 2px var(--accent)' },
						{ boxShadow: '0 0 0 0 var(--accent)' }
					], {
						duration: 300,
						easing: 'ease-out'
					});
				}
			}
			
			if (e.key == "Escape") {
				document.querySelectorAll('.card.selected').forEach(e => e.classList.remove("selected"));
			}
			
			if (!editing && e.key == "F2") {
				document.querySelector('.tab-content.active').querySelector('.card.selected .card-content')?.ondblclick?.();
			}
		};
		
		document.onpaste = async function (e) {
			if (!editing) {
				const cards = await createCardFromDataTransfer(e.clipboardData);
				document.querySelector('.tab-content.active').append(...cards);
			}
		};
		
		let unloadPromise;
		let loadPromise;
		async function updateTheme() {
			let isDark = config.colorscheme == "dark"
			if (config.colorscheme == "system") {
				let { colorscheme } = await $quickerSp('获取主题颜色', {});
				isDark = /dark/.test(colorscheme) || colorscheme == null && window.matchMedia("(prefers-color-scheme: dark)").matches
			}
			document.documentElement.classList.toggle("dark", isDark)
		}
		window.chrome.webview.addEventListener('message', async (event) => {
			if (event.data.op != "customMessage") return
			if (event.data.action == "closingWindow") {
				if (unloadPromise) await unloadPromise;
				window.close();
				return;
			}
			if (event.data.action == "loadData") {
				if (loadPromise) await loadPromise;
				let { resolve, reject, promise } = Promise.withResolvers();
				loadPromise = promise;
				let { data = [], metadata = {} } = event.data || {};
				document.querySelectorAll('.tab-head').forEach(e => e.remove());
				document.querySelectorAll('.tab-content').forEach(e => e.remove());
				document.body.classList.remove('manage');
				Object.assign(config, metadata);
				updateTheme();
				for (let tc of data) {
					let tab = createTab(tc.name);
					for (let c of tc.cards) {
						let card = await createCard(c.type, c.content, c.args);
						tab.contentDiv.append(card)
					}
				}
				if (data.length == 0) createTab().activate();
				else (document.querySelectorAll('.tab-head')[metadata.activeTabN] ?? document.querySelector('.tab-head')).activate();
				window.onbeforeunload = (e) => { unloadPromise = saveData(); }
				resolve();
			}
			if (event.data.action == "createCard") {
				let tab = document.querySelector('.tab-head.active');
				let { type, content } = event.data;
				let card;
				if (type == "file") {
					for (let file of content.replace(/\r/g, "").split("\n")) {
						card = await createFileCard(file);
					}
				} else if (type == "html") {
					card = await createHTMLCard(content);
					if (!config.richin) card.type = "text";
				} else {
					card = await createTextCard(content);
				}
				tab.contentDiv.append(card);
			}
		});
		
		window.onload = () => { $quickerSp('加载数据', {}) }
	</script>
</body>
</html>