<template>
  <div class="tool-page">
    <!-- 浮层提示 -->
    <Transition name="toast">
      <div v-if="toastMessage" class="toast-notification" :class="toastType">
        <div class="toast-content">
          <i v-if="toastType === 'error'" class="fas fa-circle-exclamation"></i>
          <i v-else class="fas fa-circle-info"></i>
          <span>{{ toastMessage }}</span>
        </div>
        <button @click="closeToast" class="toast-close-btn" title="关闭">
          <i class="fas fa-xmark"></i>
        </button>
      </div>
    </Transition>
    
    <div class="main-container">
      <!-- 左侧侧栏（历史记录） -->
      <div class="sidebar" :class="{ 'sidebar-open': sidebarOpen }">
        <div class="sidebar-header">
          <h3>历史记录</h3>
          <button @click="toggleSidebar" class="close-btn">×</button>
        </div>
        <div class="sidebar-content">
          <div v-if="historyList.length === 0" class="empty-history">
            暂无历史记录
          </div>
          <div
            v-for="(item, index) in historyList"
            :key="index"
            class="history-item"
            @click="loadHistory(item)"
          >
            <div class="history-header">
              <span class="history-type">{{ item.type === 'encode' ? '编码' : '解码' }}</span>
              <span class="history-encoding">{{ 
                item.encodingType === 'base64' ? 'Base64' : 
                item.encodingType === 'url' ? 'URL' : 
                item.encodingType === 'unicode' ? 'Unicode' : 
                item.encodingType === 'zlib' ? 'Zlib' :
                item.encodingType
              }}</span>
              <span class="history-time">{{ formatTime(item.time) }}</span>
            </div>
            <div class="history-preview">{{ truncateText(item.input, 50) }}</div>
          </div>
        </div>
      </div>

      <!-- 主内容区域 -->
      <div class="content-wrapper" :class="{ 'sidebar-pushed': sidebarOpen }">
        <!-- 左侧输入区域 -->
        <div class="left-panel" :style="{ width: leftPanelWidth + '%' }">
        <div class="panel-toolbar">
          <div class="view-tabs">
            <button class="view-tab active">输入</button>
          </div>
          <div class="toolbar-actions">
            <div class="encoding-type-selector">
              <button
                @click="encodingType = 'base64'"
                :class="['type-btn', { active: encodingType === 'base64' }]"
                title="Base64编码"
              >
                Base64
              </button>
              <button
                @click="encodingType = 'url'"
                :class="['type-btn', { active: encodingType === 'url' }]"
                title="URL编码"
              >
                URL
              </button>
              <button
                @click="encodingType = 'unicode'"
                :class="['type-btn', { active: encodingType === 'unicode' }]"
                title="Unicode编码"
              >
                Unicode
              </button>
              <button
                @click="encodingType = 'zlib'"
                :class="['type-btn', { active: encodingType === 'zlib' }]"
                title="Zlib 压缩/解压"
              >
                Zlib
              </button>
            </div>
            <button @click="copyInputToClipboard" class="toolbar-icon-btn" title="复制">
              <i class="far fa-copy"></i>
            </button>
            <button @click="pasteFromClipboard" class="toolbar-icon-btn" title="粘贴">
              <i class="far fa-paste"></i>
            </button>
            <button @click="encode" class="toolbar-icon-btn" title="编码">
              <i class="fa-solid fa-code"></i>
            </button>
            <button @click="decode" class="toolbar-icon-btn" title="解码">
              <svg viewBox="150 -50 1100 1250" xmlns="http://www.w3.org/2000/svg" width="17" height="17"><path d="M285.352637 0.003641h111.956538v114.687184h-111.956538v282.621991a110.682235 110.682235 0 0 1-33.313896 81.282266 110.682235 110.682235 0 0 1-81.282266 33.313896 110.682235 110.682235 0 0 1 81.282266 33.313897 110.682235 110.682235 0 0 1 33.313896 81.282266v282.621991h111.956538v114.687184h-111.956538a188.050574 188.050574 0 0 1-80.007964-40.049493 93.570179 93.570179 0 0 1-34.67922-74.637691v-226.643722a110.682235 110.682235 0 0 0-33.313896-81.282267 110.682235 110.682235 0 0 0-81.282267-33.313896H0v-111.956537h55.978269a110.682235 110.682235 0 0 0 81.282266-33.313897 110.682235 110.682235 0 0 0 33.313896-81.282266V114.690825A113.776969 113.776969 0 0 1 285.261616 0.003641z m794.61835 0a113.776969 113.776969 0 0 1 114.687184 114.687184v226.643722a113.776969 113.776969 0 0 0 114.687185 114.687184H1365.323624v111.956538h-55.978268a113.776969 113.776969 0 0 0-114.687185 114.687184v226.643722a113.776969 113.776969 0 0 1-114.687184 114.687184h-111.956537V909.309175h111.956537V626.687184a113.776969 113.776969 0 0 1 114.687184-114.687184 113.776969 113.776969 0 0 1-114.687184-114.687184V114.690825h-111.956537V0.003641h111.956537zM682.661812 682.665453a54.612945 54.612945 0 0 1 55.978269 55.978269 58.799937 58.799937 0 0 1-16.019797 41.323795 54.612945 54.612945 0 0 1-80.007965 0 58.799937 58.799937 0 0 1-16.019797-41.323795 54.612945 54.612945 0 0 1 55.978269-55.978269z m-226.643721 0a54.612945 54.612945 0 0 1 55.978268 55.978269 58.799937 58.799937 0 0 1-16.019797 41.323795 52.246384 52.246384 0 0 1-40.049493 17.294099 59.164024 59.164024 0 0 1-58.708916-58.708916 52.246384 52.246384 0 0 1 17.294099-40.049493 58.799937 58.799937 0 0 1 41.505839-15.837754z m453.287443 0a58.799937 58.799937 0 0 1 41.323795 16.019797 52.246384 52.246384 0 0 1 17.294099 40.049493 59.164024 59.164024 0 0 1-58.708916 58.708916 52.246384 52.246384 0 0 1-40.049493-17.294099 58.799937 58.799937 0 0 1-16.019797-41.323795 54.612945 54.612945 0 0 1 55.978269-55.978269z" fill="#666666" p-id="26339"></path></svg>
            </button>
            <button @click="clearAll" class="toolbar-icon-btn" title="清空">
              <i class="far fa-trash-can"></i>
            </button>
          </div>
        </div>
        <div ref="inputContainerRef" class="editor-container">
          <div class="editor-body">
            <div class="line-numbers">
              <div v-for="n in inputLineCount" :key="n" class="line-number">{{ n }}</div>
            </div>
            <textarea
              ref="inputEditorRef"
              v-model="inputText"
              @input="updateInputLineCount"
              placeholder="请输入要编码或解码的文本"
              class="text-editor"
            ></textarea>
          </div>
        </div>
        <div class="sidebar-toggle">
          <button @click="toggleSidebar" class="toggle-btn">
            {{ sidebarOpen ? '◀' : '▶' }}
          </button>
        </div>
      </div>

      <!-- 可拖拽分割线 -->
      <div
        class="splitter"
        @mousedown="startResize"
      ></div>

      <!-- 右侧输出区域 -->
      <div class="right-panel" :style="{ width: rightPanelWidth + '%' }">
        <div class="panel-toolbar">
          <div class="view-tabs">
            <button class="view-tab active">输出</button>
          </div>
          <div class="toolbar-actions">
            <button @click="copyOutputToClipboard" class="toolbar-icon-btn" title="复制输出">
              <i class="far fa-copy"></i>
            </button>
          </div>
        </div>
        <div ref="outputContainerRef" class="editor-container">
          <div class="editor-body">
            <div class="line-numbers">
              <div v-for="n in outputLineCount" :key="n" class="line-number">{{ n }}</div>
            </div>
            <textarea
              ref="outputEditorRef"
              v-model="outputText"
              readonly
              class="text-editor output-editor"
              placeholder="编码或解码结果将显示在这里"
            ></textarea>
          </div>
        </div>
      </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, watch, onMounted, onUnmounted } from 'vue'
import { zlibSync, decompressSync } from 'fflate'
import { useLineNumberEditor } from '../composables/useLineNumberEditor'

const inputText = ref('')
const outputText = ref('')
const encodingType = ref('base64') // 'base64'、'url'、'unicode' 或 'zlib'
const leftPanelWidth = ref(50)
const rightPanelWidth = ref(50)
const isResizing = ref(false)
const {
  containerRef: inputContainerRef,
  editorRef: inputEditorRef,
  lineCount: inputLineCount,
  updateLineCount: updateInputLineCount,
  initEditor: initInputEditor,
} = useLineNumberEditor(() => inputText.value)
const {
  containerRef: outputContainerRef,
  editorRef: outputEditorRef,
  lineCount: outputLineCount,
  updateLineCount: updateOutputLineCount,
  initEditor: initOutputEditor,
} = useLineNumberEditor(() => outputText.value)
const sidebarOpen = ref(false)

// 历史记录
const historyList = ref([])
const STORAGE_KEY = 'encoder-decoder-history'
const MAX_HISTORY = 50

// 提示消息
const toastMessage = ref('')
const toastType = ref('error') // 'error' 或 'info'
let toastTimer = null

// 显示提示
const showToast = (message, type = 'error', duration = 3000) => {
  toastMessage.value = message
  toastType.value = type
  
  if (toastTimer) {
    clearTimeout(toastTimer)
  }
  
  toastTimer = setTimeout(() => {
    toastMessage.value = ''
  }, duration)
}

// 关闭提示
const closeToast = () => {
  if (toastTimer) {
    clearTimeout(toastTimer)
    toastTimer = null
  }
  toastMessage.value = ''
}

// 监听输出变化，同步行号
watch(() => outputText.value, () => {
  updateOutputLineCount()
})

// Zlib: Uint8Array -> Base64（用于显示/复制）
const bytesToBase64 = (bytes) => {
  let binary = ''
  for (let i = 0; i < bytes.length; i++) {
    binary += String.fromCharCode(bytes[i])
  }
  return btoa(binary)
}

// Zlib: Base64 -> Uint8Array（自动去除空白字符）
const base64ToBytes = (str) => {
  const clean = str.replace(/\s/g, '')
  const binary = atob(clean)
  const bytes = new Uint8Array(binary.length)
  for (let i = 0; i < binary.length; i++) {
    bytes[i] = binary.charCodeAt(i)
  }
  return bytes
}

// Unicode 编码
const encodeUnicode = (text) => {
  let result = ''
  let i = 0
  
  while (i < text.length) {
    const codePoint = text.codePointAt(i)
    
    if (codePoint > 0xFFFF) {
      // 超出 BMP 的字符，使用代理对表示
      const high = Math.floor((codePoint - 0x10000) / 0x400) + 0xD800
      const low = ((codePoint - 0x10000) % 0x400) + 0xDC00
      result += '\\u' + high.toString(16).toUpperCase().padStart(4, '0')
      result += '\\u' + low.toString(16).toUpperCase().padStart(4, '0')
      i += 2 // 代理对占用两个字符位置
    } else {
      // BMP 字符
      result += '\\u' + codePoint.toString(16).toUpperCase().padStart(4, '0')
      i++
    }
  }
  
  return result
}

// Unicode 解码
const decodeUnicode = (text) => {
  try {
    let result = ''
    let i = 0
    
    while (i < text.length) {
      // 匹配 \uXXXX 格式
      if (text[i] === '\\' && i + 1 < text.length && text[i + 1] === 'u' && i + 5 < text.length) {
        const hex = text.substring(i + 2, i + 6)
        if (/^[0-9a-fA-F]{4}$/.test(hex)) {
          const code1 = parseInt(hex, 16)
          
          // 检查是否是高代理（surrogate high）
          if (code1 >= 0xD800 && code1 <= 0xDBFF && i + 11 < text.length) {
            // 检查下一个是否是低代理
            if (text[i + 6] === '\\' && text[i + 7] === 'u') {
              const hex2 = text.substring(i + 8, i + 12)
              if (/^[0-9a-fA-F]{4}$/.test(hex2)) {
                const code2 = parseInt(hex2, 16)
                // 检查是否是低代理（surrogate low）
                if (code2 >= 0xDC00 && code2 <= 0xDFFF) {
                  // 组合代理对
                  const codePoint = 0x10000 + ((code1 - 0xD800) << 10) + (code2 - 0xDC00)
                  result += String.fromCodePoint(codePoint)
                  i += 12
                  continue
                }
              }
            }
          }
          
          // 普通字符或单独的代理
          result += String.fromCharCode(code1)
          i += 6
          continue
        }
      }
      
      // 匹配 \UXXXXXXXX 格式（8位十六进制）
      if (text[i] === '\\' && i + 1 < text.length && text[i + 1] === 'U' && i + 9 < text.length) {
        const hex = text.substring(i + 2, i + 10)
        if (/^[0-9a-fA-F]{8}$/.test(hex)) {
          const code = parseInt(hex, 16)
          if (code > 0x10FFFF) {
            throw new Error('无效的 Unicode 码点：超出范围')
          }
          result += String.fromCodePoint(code)
          i += 10
          continue
        }
      }
      
      // 普通字符
      result += text[i]
      i++
    }
    
    return result
  } catch (e) {
    throw new Error('Unicode 解码失败：' + e.message)
  }
}

const encode = () => {
  if (!inputText.value.trim()) {
    showToast('请输入要编码的文本')
    return
  }
  try {
    let result = ''
    if (encodingType.value === 'base64') {
      result = btoa(unescape(encodeURIComponent(inputText.value)))
    } else if (encodingType.value === 'url') {
      result = encodeURIComponent(inputText.value)
    } else if (encodingType.value === 'unicode') {
      result = encodeUnicode(inputText.value)
    } else if (encodingType.value === 'zlib') {
      const utf8 = new TextEncoder().encode(inputText.value)
      // 使用 zlib 格式，与 Java Deflater/Inflater 默认格式兼容
      const compressed = zlibSync(utf8)
      result = bytesToBase64(compressed)
    }
    outputText.value = result
    
    // 保存到历史记录
    saveToHistory({
      type: 'encode',
      encodingType: encodingType.value,
      input: inputText.value,
      output: result
    })
    
    showToast('编码成功', 'info', 2000)
  } catch (e) {
    showToast('编码失败：' + e.message)
    outputText.value = ''
  }
}

const decode = () => {
  if (!inputText.value.trim()) {
    showToast('请输入要解码的字符串')
    return
  }
  try {
    let result = ''
    if (encodingType.value === 'base64') {
      result = decodeURIComponent(escape(atob(inputText.value)))
    } else if (encodingType.value === 'url') {
      result = decodeURIComponent(inputText.value)
    } else if (encodingType.value === 'unicode') {
      result = decodeUnicode(inputText.value)
    } else if (encodingType.value === 'zlib') {
      const compressed = base64ToBytes(inputText.value.trim())
      // decompressSync 自动识别 zlib / raw deflate / gzip，可解 Java Deflater 输出
      const decompressed = decompressSync(compressed)
      result = new TextDecoder().decode(decompressed)
    }
    outputText.value = result
    
    // 保存到历史记录
    saveToHistory({
      type: 'decode',
      encodingType: encodingType.value,
      input: inputText.value,
      output: result
    })
    
    showToast('解码成功', 'info', 2000)
  } catch (e) {
    const typeName = encodingType.value === 'base64' ? 'Base64' : 
                     encodingType.value === 'url' ? 'URL' : 
                     encodingType.value === 'unicode' ? 'Unicode' : 
                     encodingType.value === 'zlib' ? 'Zlib' :
                     encodingType.value
    showToast(`解码失败：请检查输入是否为有效的${typeName}编码字符串`)
    outputText.value = ''
  }
}

const clearAll = () => {
  inputText.value = ''
  outputText.value = ''
  updateInputLineCount()
  updateOutputLineCount()
  showToast('已清空', 'info', 2000)
}

// 复制输入到剪贴板
const copyInputToClipboard = async () => {
  if (!inputText.value.trim()) {
    showToast('输入内容为空，无法复制')
    return
  }
  try {
    await navigator.clipboard.writeText(inputText.value)
    showToast('已复制输入到剪贴板', 'info', 2000)
  } catch (e) {
    showToast('复制失败：' + e.message)
  }
}

// 复制输出到剪贴板
const copyOutputToClipboard = async () => {
  if (!outputText.value.trim()) {
    showToast('输出内容为空，无法复制')
    return
  }
  try {
    await navigator.clipboard.writeText(outputText.value)
    showToast('已复制输出到剪贴板', 'info', 2000)
  } catch (e) {
    showToast('复制失败：' + e.message)
  }
}

// 从剪贴板粘贴
const pasteFromClipboard = async () => {
  if (navigator.clipboard && navigator.clipboard.readText) {
    try {
      const text = await navigator.clipboard.readText()
      if (text.trim()) {
        inputText.value = text
        updateInputLineCount()
      } else {
        showToast('剪贴板内容为空')
      }
    } catch (e) {
      if (inputEditorRef.value) {
        inputEditorRef.value.focus()
        showToast('请按 Ctrl+V 或 Cmd+V 粘贴内容', 'info', 3000)
      } else {
        showToast('无法访问编辑器，请手动粘贴内容')
      }
    }
  } else {
    if (inputEditorRef.value) {
      inputEditorRef.value.focus()
      showToast('请按 Ctrl+V 或 Cmd+V 粘贴内容', 'info', 3000)
    }
  }
}

// 拖拽调整宽度
const startResize = (e) => {
  isResizing.value = true
  document.addEventListener('mousemove', handleResize)
  document.addEventListener('mouseup', stopResize)
  e.preventDefault()
}

const handleResize = (e) => {
  if (!isResizing.value) return
  
  const container = document.querySelector('.content-wrapper')
  if (!container) return
  
  const containerWidth = container.offsetWidth
  const mouseX = e.clientX - container.getBoundingClientRect().left
  const percentage = (mouseX / containerWidth) * 100
  
  // 限制在20%到80%之间
  const leftPercent = Math.max(20, Math.min(80, percentage))
  const rightPercent = 100 - leftPercent
  
  leftPanelWidth.value = leftPercent
  rightPanelWidth.value = rightPercent
}

const stopResize = () => {
  isResizing.value = false
  document.removeEventListener('mousemove', handleResize)
  document.removeEventListener('mouseup', stopResize)
}

// 保存到历史记录
const saveToHistory = (item) => {
  const historyItem = {
    ...item,
    time: Date.now()
  }
  
  // 从localStorage读取现有历史
  let history = []
  try {
    const stored = localStorage.getItem(STORAGE_KEY)
    if (stored) {
      history = JSON.parse(stored)
    }
  } catch (e) {
    // 读取历史记录失败，忽略错误
  }
  
  // 避免重复保存相同的记录
  const lastHistory = history[0]
  if (lastHistory && 
      lastHistory.type === historyItem.type &&
      lastHistory.encodingType === historyItem.encodingType &&
      lastHistory.input === historyItem.input &&
      lastHistory.output === historyItem.output) {
    return
  }
  
  // 添加到开头
  history.unshift(historyItem)
  
  // 限制最多50条
  if (history.length > MAX_HISTORY) {
    history = history.slice(0, MAX_HISTORY)
  }
  
  // 保存到localStorage
  try {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(history))
    loadHistoryList()
  } catch (e) {
    // 保存历史记录失败，忽略错误
  }
}

// 加载历史记录列表
const loadHistoryList = () => {
  try {
    const stored = localStorage.getItem(STORAGE_KEY)
    if (stored) {
      historyList.value = JSON.parse(stored)
    }
  } catch (e) {
    // 加载历史记录失败，重置为空数组
    historyList.value = []
  }
}

// 加载历史记录
const loadHistory = (item) => {
  inputText.value = item.input
  outputText.value = item.output
  encodingType.value = item.encodingType
  updateInputLineCount()
  updateOutputLineCount()
}

// 切换侧栏
const toggleSidebar = () => {
  sidebarOpen.value = !sidebarOpen.value
}

// 格式化时间
const formatTime = (timestamp) => {
  const date = new Date(timestamp)
  const now = new Date()
  const diff = now - date
  
  if (diff < 60000) return '刚刚'
  if (diff < 3600000) return Math.floor(diff / 60000) + '分钟前'
  if (diff < 86400000) return Math.floor(diff / 3600000) + '小时前'
  
  return date.toLocaleString('zh-CN', {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit'
  })
}

// 截断文本
const truncateText = (text, maxLength) => {
  if (text.length <= maxLength) return text
  return text.substring(0, maxLength) + '...'
}

onMounted(() => {
  initInputEditor()
  initOutputEditor()
  loadHistoryList()
})

onUnmounted(() => {
  document.removeEventListener('mousemove', handleResize)
  document.removeEventListener('mouseup', stopResize)
  if (toastTimer) {
    clearTimeout(toastTimer)
  }
})
</script>

<style scoped>
/* 浮层提示样式 */
.toast-notification {
  position: fixed;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1000;
  min-width: 300px;
  max-width: 90%;
  padding: 0.75rem 1rem;
  border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  display: flex;
  align-items: center;
  font-size: 0.875rem;
}

.toast-notification.error {
  background: #fff5f5;
  color: #c33;
  border: 1px solid #ffcccc;
}

.toast-notification.info {
  background: #f0f9ff;
  color: #0369a1;
  border: 1px solid #bae6fd;
}

.toast-content {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1;
  min-width: 0;
}

.toast-content svg,
.toast-content i {
  flex-shrink: 0;
}

.toast-content span {
  flex: 1;
  word-break: break-word;
}

.toast-close-btn {
  flex-shrink: 0;
  margin-left: 0.75rem;
  padding: 0.25rem;
  border: none;
  background: transparent;
  border-radius: 4px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: inherit;
  opacity: 0.6;
  transition: all 0.2s;
  width: 20px;
  height: 20px;
}

.toast-close-btn:hover {
  opacity: 1;
  background: rgba(0, 0, 0, 0.08);
}

.toast-notification.error .toast-close-btn:hover {
  background: rgba(204, 51, 51, 0.15);
}

.toast-notification.info .toast-close-btn:hover {
  background: rgba(3, 105, 161, 0.15);
}

.toast-close-btn:active {
  opacity: 0.8;
}

.toast-close-btn svg,
.toast-close-btn i {
  display: block;
  font-size: 14px;
}

/* 浮层提示动画 */
.toast-enter-active {
  animation: slideUp 0.3s ease-out;
}

.toast-leave-active {
  animation: slideDown 0.3s ease-in;
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}

@keyframes slideDown {
  from {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
  to {
    opacity: 0;
    transform: translateX(-50%) translateY(20px);
  }
}

.tool-page {
  height: calc(100vh - 64px);
  display: flex;
  flex-direction: column;
  margin: -1rem;
  padding: 0;
  background: #ffffff;
}

.main-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;
  background: #ffffff;
}

/* 侧栏样式 */
.sidebar {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 300px;
  background: #ffffff;
  border-right: 1px solid #e5e5e5;
  transform: translateX(-100%);
  transition: transform 0.3s ease;
  z-index: 10;
  display: flex;
  flex-direction: column;
  box-shadow: 2px 0 8px rgba(0, 0, 0, 0.05);
}

.sidebar-open {
  transform: translateX(0);
}

.content-wrapper.sidebar-pushed {
  margin-left: 300px;
}

.sidebar-header {
  padding: 1rem;
  border-bottom: 1px solid #e5e5e5;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: #ffffff;
}

.sidebar-header h3 {
  margin: 0;
  font-size: 1rem;
  color: #1a1a1a;
  font-weight: 500;
}

.close-btn {
  background: none;
  border: none;
  font-size: 1.5rem;
  cursor: pointer;
  color: #666666;
  padding: 0;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 0.2s;
}

.close-btn:hover {
  color: #1a1a1a;
}

.sidebar-content {
  flex: 1;
  overflow-y: auto;
  padding: 0.5rem;
  background: #ffffff;
}

.empty-history {
  padding: 2rem;
  text-align: center;
  color: #999999;
  font-size: 0.875rem;
}

.history-item {
  padding: 0.75rem;
  margin-bottom: 0.5rem;
  background: #ffffff;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.2s;
  border: 1px solid #e5e5e5;
}

.history-item:hover {
  background: #f5f5f5;
  border-color: #d0d0d0;
}

.history-header {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0.25rem;
  flex-wrap: wrap;
}

.history-type {
  font-size: 0.75rem;
  color: #666666;
  background: #f5f5f5;
  padding: 0.125rem 0.5rem;
  border-radius: 3px;
  font-weight: 500;
}

.history-encoding {
  font-size: 0.75rem;
  color: #666666;
  background: #f0f9ff;
  padding: 0.125rem 0.5rem;
  border-radius: 3px;
  font-weight: 500;
}

.history-time {
  font-size: 0.75rem;
  color: #999999;
  margin-left: auto;
}

.history-preview {
  font-size: 0.875rem;
  color: #1a1a1a;
  font-family: 'Courier New', monospace;
  word-break: break-all;
}

.content-wrapper {
  flex: 1;
  display: flex;
  position: relative;
  background: #ffffff;
  transition: margin-left 0.3s ease;
}

.left-panel,
.right-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  background: #ffffff;
}

.left-panel {
  position: relative;
}

/* 面板工具栏 */
.panel-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0;
  background: #ffffff;
  border-bottom: 1px solid #e5e5e5;
  min-height: 40px;
}

.view-tabs {
  display: flex;
  gap: 0;
  padding-left: 0.5rem;
}

.view-tab {
  padding: 0.5rem 1rem;
  border: none;
  background: transparent;
  color: #666666;
  cursor: pointer;
  font-size: 0.875rem;
  font-weight: 500;
  transition: all 0.2s;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.view-tab:hover {
  color: #1a1a1a;
  background: #f5f5f5;
}

.view-tab.active {
  color: #ffffff;
  background: #1a1a1a;
  border-bottom-color: #1a1a1a;
}

.toolbar-actions {
  display: flex;
  gap: 0.25rem;
  padding: 0.25rem 0.5rem;
  align-items: center;
}

.encoding-type-selector {
  display: flex;
  gap: 0.25rem;
  margin-right: 0.5rem;
  padding-right: 0.5rem;
  border-right: 1px solid #e5e5e5;
}

.type-btn {
  padding: 0.25rem 0.75rem;
  border: 1px solid #e5e5e5;
  border-radius: 3px;
  background: transparent;
  color: #666666;
  font-size: 0.8125rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;
}

.type-btn:hover {
  background: #f5f5f5;
  color: #1a1a1a;
  border-color: #d0d0d0;
}

.type-btn.active {
  background: #1a1a1a;
  color: #ffffff;
  border-color: #1a1a1a;
}

.toolbar-icon-btn {
  padding: 0.375rem;
  border: none;
  background: transparent;
  border-radius: 3px;
  cursor: pointer;
  transition: all 0.2s;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  color: #666666;
}

.toolbar-icon-btn:hover {
  background: #f5f5f5;
  color: #1a1a1a;
}

.toolbar-icon-btn:active {
  background: #e5e5e5;
}

.toolbar-icon-btn svg,
.toolbar-icon-btn i {
  display: block;
  font-size: 14px;
}

.text-editor {
  flex: 1;
  width: 0;
  min-width: 0;
  padding: 1rem 1rem 1rem 3rem;
  border: none;
  font-family: 'Courier New', monospace;
  font-size: 14px;
  resize: none;
  outline: none;
  background: #ffffff;
  color: #1a1a1a;
  line-height: 1.6;
  overflow: hidden;
  box-sizing: border-box;
}

.text-editor:focus {
  background: #ffffff;
}

.text-editor::placeholder {
  color: #999999;
}

.output-editor {
  background: #fafafa;
  color: #1a1a1a;
}

/* 分割线 */
.splitter {
  width: 1px;
  background: #e5e5e5;
  cursor: col-resize;
  position: relative;
  flex-shrink: 0;
  transition: background 0.2s;
}

.splitter:hover {
  background: #d0d0d0;
  width: 2px;
}

.splitter::before {
  content: '';
  position: absolute;
  left: -2px;
  right: -2px;
  top: 0;
  bottom: 0;
}

/* 侧栏切换按钮 */
.sidebar-toggle {
  position: absolute;
  left: 0;
  bottom: 1rem;
  z-index: 5;
}

.toggle-btn {
  width: 32px;
  height: 48px;
  background: #1a1a1a;
  color: #ffffff;
  border: none;
  border-radius: 0 4px 4px 0;
  cursor: pointer;
  font-size: 0.875rem;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
  box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
}

.toggle-btn:hover {
  background: #333333;
}

@media (max-width: 768px) {
  .tool-page {
    padding: 0;
    margin: -1rem;
    height: calc(100vh - 64px + 2rem);
  }
  
  .sidebar {
    width: 80%;
    max-width: 300px;
  }
  
  .left-panel,
  .right-panel {
    min-width: 0;
  }
  
  .view-tabs {
    padding-left: 0.25rem;
  }
  
  .view-tab {
    padding: 0.5rem 0.75rem;
    font-size: 0.8125rem;
  }
  
  .encoding-type-selector {
    margin-right: 0.25rem;
    padding-right: 0.25rem;
  }
  
  .type-btn {
    padding: 0.25rem 0.5rem;
    font-size: 0.75rem;
  }
  
  .text-editor {
    padding-left: 2.5rem;
  }
  
  .toast-notification {
    bottom: 10px;
    left: 1rem;
    right: 1rem;
    transform: none;
    min-width: auto;
    max-width: none;
  }
  
  @keyframes slideUp {
    from {
      opacity: 0;
      transform: translateY(20px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }
  
  @keyframes slideDown {
    from {
      opacity: 1;
      transform: translateY(0);
    }
    to {
      opacity: 0;
      transform: translateY(20px);
    }
  }
}
</style>
