<template>
  <el-container class="home-page">
    <!-- 左侧菜单区域 -->
    <el-aside :width="isCollapsed ? '64px' : '250px'" class="sidebar">
      <div class="sidebar-header">
        <span v-if="!isCollapsed" style="margin-right: 15px; font-weight: bold;">笔记分类</span>
        <el-button v-if="!isCollapsed" type="primary" size="small" @click="showCreateGroupDialog = true" circle>
          <el-icon><Plus /></el-icon>
        </el-button>
        <el-button @click="isCollapsed = !isCollapsed" type="primary" size="small" circle>
          <el-icon>
            <Fold v-if="!isCollapsed" />
            <Expand v-else />
          </el-icon>
        </el-button>
      </div>

      <el-menu
        :default-active="activeMenu"
        class="el-menu-vertical-demo"
        :collapse="isCollapsed"
        popper-effect="light"
        :collapse-transition="false"
      >
        <!-- 递归菜单组件 -->
        <template v-for="menu in categoryTree" :key="menu.id">
          <component :is="renderMenu(menu)" />
        </template>
      </el-menu>
    </el-aside>

    <!-- 右侧内容区域 -->
    <el-container>
      <el-main class="content">
        <div v-if="selectedFile" class="file-preview">
          <el-header class="preview-header">
            <h2 class="preview-title">
              {{ selectedFile.title }}
              <el-icon class="edit-icon" @click="openRenameDialog(selectedFile, 'file')"><Edit /></el-icon>
            </h2>
            <div class="actions">
              <el-button v-if="!showEditor" type="primary" @click="selectedFile = null">清空</el-button>
              <el-button v-if="!showEditor && userStore.isLoggedIn" type="primary" @click="editNote(selectedFile); isCollapsed = true">编辑</el-button>
              <el-button v-if="!showEditor && userStore.isLoggedIn" type="danger" @click="deleteNote(selectedFile)">删除</el-button>
              <el-button v-if="showEditor" type="primary" @click="showEditor = !showEditor; previewFile(editData)">返回</el-button>
              <el-button v-if="showEditor && userStore.isLoggedIn" type="success" @click="handleSave(vditor.getValue())">保存</el-button>
              <span v-if="showEditor" class="save-status">{{ saveStatus }}</span>
              <el-button v-if="!showEditor" type="success" @click="handleExportMd">导出为.md</el-button>
            </div>
          </el-header>
          <div v-if="!showEditor" v-html="previewHtml" class="markdown-preview"></div>
          <!-- Vditor 编辑器 -->
          <div v-show="showEditor" id="vditor" class="vditor" />
        </div>

        <div v-else>
          <el-header class="header">
            <h1>我的笔记</h1>
            <div class="actions">
              <el-input
                v-model="searchKeyword"
                placeholder="搜索笔记标题"
                class="search-input"
                @keyup.enter="handleSearch"
              >
                <template #append>
                  <el-button @click="handleSearch">
                    <el-icon><Search /></el-icon>
                  </el-button>
                </template>
              </el-input>
              <div v-if="userStore.isLoggedIn">
                <span>欢迎, {{ userStore.userInfo?.username }}</span>
                <el-button type="danger" @click="handleLogout">退出</el-button>
              </div>
              <div v-else>
                <el-button type="primary" @click="goToLogin">登录</el-button>
                <el-button @click="goToRegister">注册</el-button>
              </div>
              <el-button v-if="userStore.isLoggedIn" type="primary" @click="showCreateNoteDialog = true">新建笔记</el-button>
              <el-upload
                  v-if="userStore.isLoggedIn"
                class="upload-btn"
                action=""
                :show-file-list="false"
                :before-upload="handleMarkdownUpload"
                accept=".md"
              >
                <el-button type="success">上传Markdown</el-button>
              </el-upload>
            </div>
          </el-header>

          <div v-if="groupMarkdownFiles.length > 0" class="file-list">
            <el-card v-for="file in groupMarkdownFiles" :key="file.id" shadow="hover" class="file-item">
              <div @click="previewFile(file)" class="file-title">{{ file.title }}</div>
            </el-card>
          </div>
          <el-empty v-else description="暂无笔记，请创建或上传" />
        </div>

        <!-- 分类创建对话框 -->
        <el-dialog v-model="showCreateGroupDialog" title="新建分类" width="400px" @close="resetGroupForm">
          <el-form :model="newGroupForm" :rules="groupFormRules" ref="groupFormRef" label-width="80px">
            <el-form-item label="父级分类">
              <el-cascader
                  v-model="newGroupForm.parentId"
                  :options="categoryCascaderOptions"
                  :props="{ checkStrictly: true, emitPath: false }"
                  clearable
                  placeholder="不选则为一级分类"
                  style="width: 100%;"
              ></el-cascader>
            </el-form-item>
            <el-form-item label="分类名称" prop="name">
              <el-input v-model="newGroupForm.name" autocomplete="off"></el-input>
            </el-form-item>
          </el-form>
          <template #footer>
            <el-button @click="showCreateGroupDialog = false">取消</el-button>
            <el-button type="primary" @click="createGrouping">确定</el-button>
          </template>
        </el-dialog>

        <!-- 笔记创建对话框 -->
        <el-dialog v-model="showCreateNoteDialog" title="新建笔记" width="400px" @close="resetNoteForm">
          <el-form :model="newNoteForm" :rules="noteFormRules" ref="noteFormRef" label-width="80px">
            <el-form-item label="笔记标题" prop="title">
              <el-input v-model="newNoteForm.title" autocomplete="off"></el-input>
            </el-form-item>
            <el-form-item label="选择分类" prop="groupingId">
              <el-cascader
                  v-model="newNoteForm.groupingId"
                  :options="categoryTree"
                  :props="{ checkStrictly: true, emitPath: false }"
                  clearable
                  placeholder="请选择笔记所属分类"
                  style="width: 100%;"
              ></el-cascader>
            </el-form-item>
          </el-form>
          <template #footer>
            <el-button @click="showCreateNoteDialog = false">取消</el-button>
            <el-button type="primary" @click="createNote">确定</el-button>
          </template>
        </el-dialog>

        <!-- 重命名对话框 -->
        <el-dialog v-model="showRenameDialog" title="重命名" width="400px">
          <el-input v-model="newName" placeholder="请输入新名称"></el-input>
          <template #footer>
            <el-button @click="showRenameDialog = false">取消</el-button>
            <el-button type="primary" @click="handleRename">确定</el-button>
          </template>
        </el-dialog>

        <!-- 导入选择分类对话框 -->
        <el-dialog v-model="showSelectGroupDialog" title="选择导入的分类" width="400px">
          <el-cascader
              v-model="importGroupId"
              :options="categoryTree"
              :props="{ checkStrictly: true, emitPath: false }"
              clearable
              placeholder="请选择要导入的分类"
              style="width: 100%;"
          ></el-cascader>
          <template #footer>
            <el-button @click="showSelectGroupDialog = false">取消</el-button>
            <el-button type="primary" @click="confirmImport">确定</el-button>
          </template>
        </el-dialog>
      </el-main>
    </el-container>
  </el-container>
</template>

<script setup>
import {onMounted, ref, nextTick, watch, h, computed} from 'vue';
import {ElMessage, ElSubMenu, ElMenuItem, ElIcon} from 'element-plus';
import Vditor from 'vditor';
import 'vditor/dist/index.css';
import {
  addGroupings,
  deleteImages, deleteMarkdown,
  groupingAll,
  markdownAll, markdownList,
  Preview,
  updateMarkdown, uploadImage,
  searchMarkdown,
  updateGroupingName,
  updateMarkdownTitle
} from '@/api/CommonApi.js'
import { Plus, Fold, Expand, Folder, Document, Search, Edit } from "@element-plus/icons-vue";
import { useUserStore } from '../stores/user';
import { useRouter } from 'vue-router';

const userStore = useUserStore();
const router = useRouter();
const searchKeyword = ref('');

const markdownFiles = ref([]);
const categoryTree = ref([]);
const groupMarkdownFiles = ref({});
const showEditor = ref(false);
const selectedFile = ref(null);
const activeMenu = ref('all');
const isCollapsed = ref(false);
const showCreateGroupDialog = ref(false);
const showCreateNoteDialog = ref(false);
const showRenameDialog = ref(false);
const itemToRename = ref(null);
const newName = ref('');
const showSelectGroupDialog = ref(false);
const importGroupId = ref(null);
const fileToImport = ref(null);

const groupFormRef = ref(null);
const newGroupForm = ref({ name: '', parentId: null });
const groupFormRules = ref({
  name: [{ required: true, message: '请输入分类名称', trigger: 'blur' }],
});

const noteFormRef = ref(null);
const newNoteForm = ref({
  id: null,
  title: '',
  groupingId: null,
  fileName: '',
  content: ''
});
const noteFormRules = ref({
  title: [{ required: true, message: '请输入笔记标题', trigger: 'blur' }],
  groupingId: [{ required: true, message: '请选择分类', trigger: 'change' }],
});

const editData=ref(null)
const imageUrls = ref([]);
const originalImages = ref([]);

const vditor = ref(null);
const previewHtml = ref('');
const saveStatus = ref('空闲');
let debounceTimer = null;

const categoryCascaderOptions = computed(() => {
  return [{ id: 0, grouping: '根分类', value: 0, label: '根分类' }, ...categoryTree.value];
});

const initVditor = () => {
  vditor.value = new Vditor('vditor', {
    height: 'calc(100vh - 120px)',
    mode: 'ir',
    after: () => {
      if (editData.value) {
        vditor.value.setValue(editData.value.content);
      }
    },
    input: (value) => {
      debouncedSave(value);
    },
    upload: {
      accept: 'image/*',
      handler(files) {
        handleImageUpload(files);
      },
    },
  });
};

const buildTree = (items, parentId = 0) => {
  return items
      .filter(item => +item.parentId === +parentId)
      .map(item => {
        const children = buildTree(items, item.id);
        return {
          ...item,
          value: item.id,
          label: item.grouping,
          children: children.length > 0 ? children : undefined,
        };
      });
};

const fetchGroupings = async () => {
  try {
    const response = await groupingAll("");
    const allCategories = response.data || [];
    categoryTree.value = buildTree(allCategories);
  } catch (error) {
    console.error('获取分组失败:', error);
    ElMessage.error('获取分组失败: ' + (error.response?.data?.message || error.message));
    categoryTree.value = [];
  }
};

const selectFile = async (data) => {
  const promise = await markdownList(data.id);
  groupMarkdownFiles.value = promise.data;
  selectedFile.value = null;
};

const fetchMarkdownFiles = async () => {
  try {
    const response = await markdownAll()
    markdownFiles.value = (response.data || []).map(file => ({
      ...file,
      id: String(file.id)
    }));
  } catch (error) {
    ElMessage.error('获取笔记列表失败: ' + error.message);
  }
};

const createGrouping = async () => {
  if (!groupFormRef.value) return;
  await groupFormRef.value.validate(async (valid) => {
    if (valid) {
      try {
        const payload = {
          name: newGroupForm.value.name,
          parentId: newGroupForm.value.parentId || 0
        };
        await addGroupings(payload);
        ElMessage.success('分类创建成功');
        showCreateGroupDialog.value = false;
        await fetchGroupings();
      } catch (error) {
        ElMessage.error('创建分类失败: ' + error.message);
      }
    }
  });
};

const resetGroupForm = () => {
  newGroupForm.value = { name: '', parentId: null };
  if (groupFormRef.value) {
    groupFormRef.value.resetFields();
  }
};

const createNote = async () => {
  if (!noteFormRef.value) return;
  await noteFormRef.value.validate(async (valid) => {
    if (valid) {
      try {
        const groupingId = newNoteForm.value.groupingId;
        if (!groupingId) {
          ElMessage.error('必须选择一个分类');
          return;
        }
        const payload = {
          id: null,
          title: newNoteForm.value.title,
          groupingId: groupingId,
          fileName: newNoteForm.value.title + '.md',
          content: ''
        };
        editData.value = payload;
        showCreateNoteDialog.value = false;
        showEditor.value = true;
        selectedFile.value = editData.value;
        await nextTick(() => {
          initVditor();
        });
      } catch (error) {
        ElMessage.error('创建笔记失败: ' + error.message);
      }
    }
  });
};

const resetNoteForm = () => {
  newNoteForm.value = { id: null, title: '', groupingId: null, fileName: '', content: '' };
  if (noteFormRef.value) {
    noteFormRef.value.resetFields();
  }
};

const renderMenu = (item) => {
  if (item.children && item.children.length > 0) {
    return h(ElSubMenu, { index: `group-${item.id}` }, {
      title: () => h('div', { class: 'menu-item-title' }, [
        h(ElIcon, () => h(Folder)),
        h('span', null, item.grouping),
        h(ElIcon, { class: 'edit-icon', onClick: (e) => { e.stopPropagation(); openRenameDialog(item, 'group'); } }, () => h(Edit))
      ]),
      default: () => item.children.map(child => renderMenu(child))
    });
  }
  return h(ElMenuItem, { index: `group-${item.id}`, onClick: () => selectFile(item) }, {
    default: () => [
      h(ElIcon, () => h(Document)),
      h('span', null, item.grouping)
    ]
  });
};

// 选择文件预览
const previewFile = async (file) => {
  if (file.id === null){
    editData.value=file
    selectedFile.value=null
    return;
  }
  try {
    const response = await Preview(file.id)

    // 确保内容为字符串
    const content = String(response.data || '');
    
    selectedFile.value = {
      ...file,
      content: content
    };
    await nextTick();
    const previewElement = document.querySelector('.markdown-preview');
    if (previewElement) {
      Vditor.preview(previewElement, content, {
        // 在这里提供一个基本的配置对象
        mode: 'light', // 或者 'dark'，可以根据当前主题动态设置
        hljs: {
          enable: true,
          style: 'github'
        }
      });
    }
  } catch (error) {
    ElMessage.error('获取笔记内容失败: ' + error.message);
  }
};

// 编辑笔记
const editNote = async (file) => {
  editData.value = file
  originalImages.value = extractImageUrls(file.content);
  showEditor.value = true;
  await nextTick(() => {
    initVditor();
  });
};

// 图片上传
const handleImageUpload=async (files) => {
  const promise = await uploadImage(files);
  if (promise.code !== 200) {
    ElMessage.error(promise.msg);
    return;
  }
  // 插入图片（确保URL格式正确）
  const imageUrl = promise.data.url.startsWith('/')
      ? `http://127.0.0.1:8084${promise.data.url}`
      : promise.data.url;
  
  vditor.value.insertValue(`![](${imageUrl})`);
}

// 在编辑页面，按Ctrl+S保存笔记，或者点击保存，对数据进行保存
const handleSave= async (content, isAutoSave = false) => {
  imageUrls.value = extractImageUrls(content);
  extractDeletedImageUrls(imageUrls.value)
  editData.value.content = content
  const filesRes = await updateMarkdown(editData.value);
  if (filesRes.code === 200) {
    // 关键修复：用后端返回的、带有ID的最新数据更新本地状态
    editData.value = filesRes.data;
    if (selectedFile.value) {
      selectedFile.value.id = filesRes.data.id; // 确保预览对象也有ID
    }

    if (!isAutoSave) {
      ElMessage.success(filesRes.msg);
    }
    await chushihua();
  } else {
    if (!isAutoSave) {
      ElMessage.error(filesRes.msg);
    }
    throw new Error(filesRes.msg);
  }
}

// 保存时获取所有的图片url
const extractImageUrls = (data) => {
  const content = data
  const urls = [];

  // 处理 URL 的内部函数
  const getPathFromUrl = (url) => {
    try {
      if (url.startsWith('http://') || url.startsWith('https://')) {
        // 使用 URL 对象解析路径
        return new URL(url).pathname;
      }
      return url; // 非 HTTP(S) URL 直接返回（如 base64）
    } catch (e) {
      return url; // 解析失败时返回原始 URL
    }
  };

  // 匹配Markdown图片语法
  const mdRegex = /!\[.*?\]\((.*?)\)/g;
  let mdMatch;
  while ((mdMatch = mdRegex.exec(content)) !== null) {
    urls.push(getPathFromUrl(mdMatch))
  }

  // 匹配HTML img标签
  const htmlRegex = /<img[^>]+src="([^">]+)"/g;
  let htmlMatch;
  while ((htmlMatch = htmlRegex.exec(content)) !== null) {
    urls.push(getPathFromUrl(htmlMatch));
  }

  // 匹配base64图片
  const base64Regex = /<img[^>]+src="(data:image\/[^;]+;base64[^">]+)"/g;
  let base64Match;
  while ((base64Match = base64Regex.exec(content)) !== null) {
    urls.push(base64Match);
  }

  // 过滤和去重
  const validUrls = urls.filter(url => {
    return url.startsWith('http') || url.startsWith('data:image');
  });
  return [...new Set(validUrls)]
};

// 笔记保存时获取要删除的图片url
const extractDeletedImageUrls = (data) => {
  const delImages = []
  // 原来的url originalImages.value
  for (let i = 0; i <originalImages.value.length; i++) {
    for (let j = 0; j <data.length; j++) {
        if (originalImages.value[i] !== data[j]){
          delImages.push(originalImages.value[i])
        }
    }
  }
  if (delImages.length>0){
    deleteImages(delImages)
  }
}

// 删除笔记
const deleteNote = async (file) => {
  try {
    await deleteMarkdown(file.id);
    ElMessage.success('删除成功');
    selectedFile.value = null;
    await chushihua()
    await selectFile(groupingId)
  } catch (error) {
    ElMessage.error('删除失败: ' + error.message);
  }
};

const debouncedSave = (content) => {
  saveStatus.value = '正在输入...';
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(async () => {
    saveStatus.value = '正在保存...';
    try {
      // 直接使用 vditor.value.getValue() 获取最新内容
      await handleSave(vditor.value.getValue(), true);
      saveStatus.value = '已保存';
    } catch (error) {
      saveStatus.value = '保存失败';
    }
  }, 2000); // 2-second delay
};

const openRenameDialog = (item, type) => {
  itemToRename.value = { ...item, type };
  newName.value = type === 'group' ? item.grouping : item.title;
  showRenameDialog.value = true;
};

const handleRename = async () => {
  if (!newName.value.trim()) {
    ElMessage.error('名称不能为空');
    return;
  }

  try {
    if (itemToRename.value.type === 'group') {
      await updateGroupingName(itemToRename.value.id, newName.value);
      ElMessage.success('分类重命名成功');
      await fetchGroupings();
    } else if (itemToRename.value.type === 'file') {
      await updateMarkdownTitle(itemToRename.value.id, newName.value);
      ElMessage.success('笔记重命名成功');
      selectedFile.value.title = newName.value;
      await fetchMarkdownFiles();
    }
    showRenameDialog.value = false;
  } catch (error) {
    ElMessage.error('重命名失败: ' + error.message);
  }
};

// 上传Markdown文件处理
const handleMarkdownUpload = (file) => {
  const reader = new FileReader();
  reader.onload = (e) => {
    fileToImport.value = {
      content: e.target.result,
      title: file.name.replace('.md', ''),
      fileName: file.name,
    };
    showSelectGroupDialog.value = true;
  };
  reader.readAsText(file);
  return false; // 阻止默认上传行为
};

const confirmImport = async () => {
  if (!importGroupId.value) {
    ElMessage.error('请选择一个分类');
    return;
  }
  try {
    await updateMarkdown({
      ...fileToImport.value,
      groupingId: importGroupId.value,
    });
    ElMessage.success('导入成功');
    showSelectGroupDialog.value = false;
    await chushihua();
  } catch (error) {
    ElMessage.error('导入失败: ' + error.message);
  }
};

onMounted(() => {
  chushihua();
  // 根据屏幕宽度初始化侧边栏状态
  if (window.innerWidth < 768) {
    isCollapsed.value = true;
  }
});

const  chushihua = async () => {
  await fetchMarkdownFiles();
  await fetchGroupings();
}

const goToLogin = () => {
  router.push('/login');
};

const goToRegister = () => {
  router.push('/register');
};

const handleLogout = () => {
  userStore.logout();
  router.push('/login');
};

const handleSearch = async () => {
  if (!searchKeyword.value) {
    await fetchMarkdownFiles();
    return;
  }
  try {
    const response = await searchMarkdown(searchKeyword.value);
    groupMarkdownFiles.value = response.data;
  } catch (error) {
    ElMessage.error('搜索失败: ' + error.message);
  }
};

const handleExportMd = () => {
  if (!selectedFile.value) return;
  const blob = new Blob([selectedFile.value.content], { type: 'text/markdown;charset=utf-8' });
  const url = window.URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.setAttribute('download', `${selectedFile.value.title}.md`);
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  window.URL.revokeObjectURL(url);
};
</script>

<style>
/* 对话框全局样式覆盖 */
.el-dialog {
  background-color: var(--bg-color-tertiary) !important;
  border-radius: 12px !important;
  box-shadow: var(--box-shadow-dark) !important;
  animation: fadeIn 0.3s ease-out, slideInUp 0.3s ease-out;
}

.el-dialog__header {
  padding: 20px 20px 10px !important;
  margin-right: 0 !important;
  border-bottom: 1px solid var(--border-color-light);
}

.el-dialog__title {
  color: var(--text-color) !important;
  font-weight: 600;
}

.el-dialog__body {
  padding: 25px 20px !important;
  color: var(--text-color-secondary);
}

.el-dialog__footer {
  padding: 10px 20px 20px !important;
  border-top: 1px solid var(--border-color-light);
}

/* Vditor 暗黑模式适配 */
.dark-theme .vditor {
  --panel-background-color: var(--bg-color-secondary) !important;
  --textarea-background-color: var(--bg-color) !important;
  --toolbar-background-color: var(--bg-color-tertiary) !important;
  --border-color: var(--border-color) !important;
  color: var(--text-color) !important;
}
.dark-theme .vditor-toolbar,
.dark-theme .vditor-content,
.dark-theme .vditor-preview {
  background-color: var(--bg-color) !important;
}
.dark-theme .vditor-toolbar__item:hover,
.dark-theme .vditor-toolbar__item--current {
  background-color: var(--primary-color-light) !important;
}
</style>

<style scoped>
.home-page {
  height: 100vh;
  background-color: var(--bg-color-secondary);
  overflow: hidden;
}

/* --- Sidebar --- */
.sidebar {
  background: var(--bg-color);
  border-right: 1px solid var(--border-color-light);
  display: flex;
  flex-direction: column;
  transition: width var(--transition-duration) ease;
}

.sidebar-header {
  padding: 15px;
  display: flex;
  justify-content: center;
  align-items: center;
  border-bottom: 1px solid var(--border-color-light);
  flex-shrink: 0;
}

.sidebar-header span {
  color: var(--text-color);
  font-size: 16px;
}

.sidebar-header .el-button {
  transition: all var(--transition-duration) ease;
}
.sidebar-header .el-button:hover {
  transform: scale(1.1);
}

.el-menu-vertical-demo {
  flex: 1;
  overflow-y: auto;
  border-right: none;
  background-color: transparent;
  padding: 8px;
}

:deep(.el-sub-menu__title),
.el-menu-item {
  border-radius: 6px;
  margin-bottom: 4px;
  color: var(--text-color-secondary);
  transition: all var(--transition-duration) ease;
}

:deep(.el-sub-menu__title:hover),
.el-menu-item:hover {
  background-color: var(--bg-color-tertiary);
  color: var(--text-color);
}

.el-menu-item.is-active {
  background-color: var(--primary-color-light);
  color: var(--primary-color) !important;
  font-weight: bold;
}

.menu-item-title {
  display: flex;
  align-items: center;
  width: 100%;
}

.menu-item-title span {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.edit-icon {
  cursor: pointer;
  margin-left: 8px;
  opacity: 0;
  transition: opacity var(--transition-duration) ease;
  color: var(--text-color-secondary);
}
.edit-icon:hover {
  color: var(--primary-color);
}

.el-sub-menu__title:hover .edit-icon,
.el-menu-item:hover .edit-icon,
.preview-title:hover .edit-icon {
  opacity: 1;
}

/* --- Content Area --- */
.content {
  padding: 24px;
  height: 100vh;
  overflow-y: auto;
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24px;
}

.header h1 {
  color: var(--text-color);
  font-size: 28px;
  font-weight: 600;
}

.actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.actions span {
  color: var(--text-color-secondary);
  font-size: 14px;
}

.search-input {
  width: 240px;
}

.file-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 20px;
}

.file-item {
  cursor: pointer;
  border-radius: 8px;
  border: 1px solid var(--border-color-light);
  background-color: var(--bg-color);
  box-shadow: var(--box-shadow-light);
  transition: all var(--transition-duration) ease;
  animation: slideInUp 0.4s ease-out;
}

.file-item:hover {
  transform: translateY(-5px);
  box-shadow: var(--box-shadow);
  border-color: var(--primary-color);
}

.file-title {
  font-size: 16px;
  font-weight: 500;
  color: var(--text-color);
  padding: 20px;
}

/* --- File Preview --- */
.file-preview {
  height: 100%;
  display: flex;
  flex-direction: column;
  background-color: var(--bg-color);
  border-radius: 8px;
  box-shadow: var(--box-shadow);
  overflow: hidden;
  animation: fadeIn 0.5s;
}

.preview-header {
  display: flex;
  padding: 12px 20px;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid var(--border-color-light);
  flex-shrink: 0;
}

.preview-title {
  display: flex;
  align-items: center;
  font-size: 20px;
  font-weight: 600;
  color: var(--text-color);
}

.preview-title .edit-icon {
  margin-left: 12px;
}

.markdown-preview, .vditor {
  flex: 1;
  padding: 20px;
  background: var(--bg-color);
  border: none;
  overflow-y: auto;
}

.save-status {
  margin-left: 10px;
  font-size: 14px;
  color: var(--text-color-placeholder);
  transition: all var(--transition-duration) ease;
}
.save-status:not(:empty) {
  animation: fadeIn 0.5s;
}

/* --- Responsive --- */
@media (max-width: 768px) {
  .sidebar {
    position: absolute;
    z-index: 1001;
    box-shadow: var(--box-shadow-dark);
  }
  .sidebar:not(.el-aside--collapse) {
    width: 250px;
  }
  .content {
    padding: 15px;
  }
  .file-list {
    grid-template-columns: 1fr;
  }
  .header h1 {
    font-size: 22px;
  }
}
</style>
