const ComponentPage = {
  mixins: [BaseMixin],
  props: {
    searchQuery: { type: String, default: '' }
  },
  data() {
    return {
      sidebarOpen: true,
      sidebarState: 'sidebar-open',

      defaultSource: ['https://3dwarehouse.sketchup.com/', '3D Warehouse'],
      onlineSources: [],
      sortOrderFolders: 1,
      autoSortEnabled: true,
      componentFolders: [],
      componentFolder: {
        folderPath: '',
        originFolderName: '',
        customFolderName: '',
        folderItems: ''
      },
      componentItems: [],
      componentItem: {
        itemPath: '',
        itemName: '',
        itemType: '',
        itemSize: '',
        thumbnailPath: ''
      },
      isOnline: false,

      currentUrl: '',
      iframeBlocked: false,
      selectedOnlineName: '',
      selectedOnlineUrl: '',

      dynamicIconPath: null,
      liveIconPath: null,
      activeModelPath: [],

      folderThumbnailPath: null,
      recentFolderPath: null,
      recentChildFolder: null,
      activeModel: true,
      activeFolderPath: null,
      selectedFolderPath: null,
      treeRootPath: null,
      treeRootItems: null,
      _browseFromLeft: false,
      selectedType: null,
      selectedItemType: null,
      actionFolderPath: null,

      selectedModels: [],
      selectedItem: null,
      selectedItems: [],
      nameExists: false,

      isDrive: false,
      isSketchupModel: false,
      folderEmpty: false,
      showSupport: false,

      showAllModels: true,
      firstShowAllModel: true,

      deepSearchResults: [],
      isDeepSearching: false,

      sidebarWidth: typeof SIDEBAR_WIDTH_DEFAULT !== 'undefined' ? SIDEBAR_WIDTH_DEFAULT : 230,
      _resizeStartX: 0,
      _resizeStartWidth: 0,
      subfolderColumnWidth: typeof SUBFOLDER_WIDTH_DEFAULT !== 'undefined' ? SUBFOLDER_WIDTH_DEFAULT : 160,
      _resizeSubfolderStartX: 0,
      _resizeSubfolderStartWidth: 0,
      subfolderColumnVisible: true,
    };
  },

  computed: {
    subfolderTreeItems() {
      if (this.treeRootItems != null) return this.treeRootItems;
      return this.componentItems || [];
    },
    filteredItems() {
      let filtered = this.componentItems;

      if (this.selectedType === 'favorites') {
        filtered = filtered.filter(itemInfo => this.favorites.includes(itemInfo.itemPath));
      }

      if (this.enableDeepSearch && this.searchQuery && this.deepSearchResults.length > 0) {
        const currentPaths = new Set(filtered.map(item => item.itemPath));
        const uniqueDeepResults = this.deepSearchResults.filter(
          item => !currentPaths.has(item.itemPath)
        );
        filtered = [...filtered, ...uniqueDeepResults];
        const query = this.searchQuery.toLowerCase();
        filtered = filtered.filter(itemInfo =>
          itemInfo.itemName && itemInfo.itemName.toLowerCase().includes(query)
        );
      } else if (this.searchQuery) {
        const query = this.searchQuery.toLowerCase();
        filtered = filtered.filter(itemInfo => itemInfo.itemName.toLowerCase().includes(query));
      }

      filtered = filtered.filter(itemInfo => !(itemInfo.itemType && String(itemInfo.itemType).includes('folder')));

      return filtered;
    },
  },

  mounted() {
    const sidebarSaved = localStorage.getItem(sidebarKey);
    if (sidebarSaved !== null) {
      const sidebar = sidebarSaved === 'true';
      this.sidebarOpen = sidebar;
      this.sidebarState = sidebar ? 'sidebar-open' : 'sidebar-closed';
    }
    const savedWidth = localStorage.getItem(sidebarWidthKey);
    if (savedWidth) {
      const w = parseInt(savedWidth, 10);
      if (!isNaN(w) && w >= (typeof SIDEBAR_WIDTH_MIN !== 'undefined' ? SIDEBAR_WIDTH_MIN : 180) && w <= (typeof SIDEBAR_WIDTH_MAX !== 'undefined' ? SIDEBAR_WIDTH_MAX : 420)) {
        this.sidebarWidth = w;
      }
    }
    const savedSubfolderWidth = localStorage.getItem(subfolderColumnWidthKey);
    if (savedSubfolderWidth) {
      const w = parseInt(savedSubfolderWidth, 10);
      if (!isNaN(w) && w >= (typeof SUBFOLDER_WIDTH_MIN !== 'undefined' ? SUBFOLDER_WIDTH_MIN : 120) && w <= (typeof SUBFOLDER_WIDTH_MAX !== 'undefined' ? SUBFOLDER_WIDTH_MAX : 280)) {
        this.subfolderColumnWidth = w;
      }
    }
    const savedSubfolderVisible = localStorage.getItem(subfolderColumnVisibleKey);
    if (savedSubfolderVisible !== null) {
      this.subfolderColumnVisible = savedSubfolderVisible === 'true';
    }

    this.isOnline = false;
    this.switchMode('local');

    const recentUrl = localStorage.getItem(recentDoorUrlKey);
    this.currentUrl = recentUrl || this.defaultSource[0];

    this.loadDetailsState();
    this.loadViewOptions();
    this.loadShowAllState();

    updateDynamicWidth('component-app');

    this.$nextTick(() => {
      this.initSortableLocal();
      this.initSortableOnline();
    });
  },

  methods: {
    initSortableLocal() {
      const sortableLocal = document.getElementById('sortableLocalComponent');
      if (sortableLocal && !sortableLocal._sortableInstance) {
        sortableLocal._sortableInstance = new Sortable(sortableLocal, {
          animation: 150,
          onEnd: () => {
            this.handleSortLocal();
          }
        });
      }
    },

    initSortableOnline() {
      const sortableOnline = document.getElementById('sortableOnlineComponent');
      if (sortableOnline && !sortableOnline._sortableInstance) {
        sortableOnline._sortableInstance = new Sortable(sortableOnline, {
          animation: 150,
          onEnd: () => {
            this.handleSortOnline();
          }
        });
      }
    },

    disableSortableLocal() {
      const sortableLocal = document.getElementById('sortableLocalComponent');
      if (sortableLocal && sortableLocal._sortableInstance) {
        sortableLocal._sortableInstance.option('disabled', true);
      }
    },

    enableSortableLocal() {
      const sortableLocal = document.getElementById('sortableLocalComponent');
      if (sortableLocal && sortableLocal._sortableInstance) {
        sortableLocal._sortableInstance.option('disabled', false);
      }
    },

    saveViewOptions() {
      const viewOptionsToSave = {
        currentViewIndex: this.currentViewIndex,
        thumbnailSize: this.thumbnailSize
      };
      localStorage.setItem(viewOptionsKey, JSON.stringify(viewOptionsToSave));
    },

    loadViewOptions() {
      const savedOptions = localStorage.getItem(viewOptionsKey);
      if (savedOptions) {
        const options = JSON.parse(savedOptions);
        this.currentViewIndex = options.currentViewIndex !== undefined ? options.currentViewIndex : 1;
        this.thumbnailSize = options.thumbnailSize || 100;
        this.applyViewOptions(this.viewOptions[this.currentViewIndex].mode);
      }
    },

    switchMode(value) {
      this.isOnline = false;
      const onlineState = 'local';
      localStorage.setItem(doorOnlineStateKey, onlineState);
    },

    startResizeSidebar(e) {
      this._resizeStartX = e.clientX;
      this._resizeStartWidth = this.sidebarWidth;
      document.addEventListener('mousemove', this._onResizeSidebarMove);
      document.addEventListener('mouseup', this._onResizeSidebarUp);
      e.preventDefault();
    },
    _onResizeSidebarMove(e) {
      const minW = typeof SIDEBAR_WIDTH_MIN !== 'undefined' ? SIDEBAR_WIDTH_MIN : 180;
      const maxW = typeof SIDEBAR_WIDTH_MAX !== 'undefined' ? SIDEBAR_WIDTH_MAX : 420;
      let w = this._resizeStartWidth + (e.clientX - this._resizeStartX);
      w = Math.max(minW, Math.min(maxW, w));
      this.sidebarWidth = w;
    },
    _onResizeSidebarUp() {
      document.removeEventListener('mousemove', this._onResizeSidebarMove);
      document.removeEventListener('mouseup', this._onResizeSidebarUp);
      if (typeof localStorage !== 'undefined' && typeof sidebarWidthKey !== 'undefined') {
        localStorage.setItem(sidebarWidthKey, String(this.sidebarWidth));
      }
    },

    startResizeSubfolderColumn(e) {
      this._resizeSubfolderStartX = e.clientX;
      this._resizeSubfolderStartWidth = this.subfolderColumnWidth;
      document.addEventListener('mousemove', this._onResizeSubfolderMove);
      document.addEventListener('mouseup', this._onResizeSubfolderUp);
      e.preventDefault();
    },
    _onResizeSubfolderMove(e) {
      const minW = typeof SUBFOLDER_WIDTH_MIN !== 'undefined' ? SUBFOLDER_WIDTH_MIN : 120;
      const maxW = typeof SUBFOLDER_WIDTH_MAX !== 'undefined' ? SUBFOLDER_WIDTH_MAX : 280;
      let w = this._resizeSubfolderStartWidth + (e.clientX - this._resizeSubfolderStartX);
      w = Math.max(minW, Math.min(maxW, w));
      this.subfolderColumnWidth = w;
    },
    _onResizeSubfolderUp() {
      document.removeEventListener('mousemove', this._onResizeSubfolderMove);
      document.removeEventListener('mouseup', this._onResizeSubfolderUp);
      if (typeof localStorage !== 'undefined' && typeof subfolderColumnWidthKey !== 'undefined') {
        localStorage.setItem(subfolderColumnWidthKey, String(this.subfolderColumnWidth));
      }
    },

    sortFolders() {
      this.sortOrderFolders = this.sortOrderFolders * -1;

      this.componentFolders.sort((a, b) => {
        if (a.customFolderName && b.customFolderName) {
          return this.sortOrderFolders === 1
            ? a.customFolderName.localeCompare(b.customFolderName)
            : b.customFolderName.localeCompare(a.customFolderName);
        } else if (a.customFolderName) {
          return -1;
        } else if (b.customFolderName) {
          return 1;
        }
        return 0;
      });

      const newOrder = this.componentFolders.map(folder => [folder.folderPath, folder.customFolderName]);
      sketchup.updateComponentFolderOrder(JSON.stringify(newOrder));

      this.$nextTick(() => {
        const sortableLocal = document.getElementById('sortableLocalComponent');
        if (sortableLocal) {
          if (sortableLocal._sortableInstance) {
            sortableLocal._sortableInstance.destroy();
            sortableLocal._sortableInstance = null;
          }
          this.initSortableLocal();
        }
      });
    },

    sortedBy(value) {
      if (!this.componentItems || this.componentItems.length === 0) return;

      this.selectedSort = value;

      const folders = this.componentItems.filter(item => item.itemType && item.itemType.includes('folder'));
      const nonFolders = this.componentItems.filter(item => item.itemType && !item.itemType.includes('folder'));

      const sortFunction = (a, b) => {
        if (value === 'nameA') {
          return a.itemName.localeCompare(b.itemName, undefined, { numeric: true, sensitivity: 'base' });
        } else if (value === 'nameZ') {
          return b.itemName.localeCompare(a.itemName, undefined, { numeric: true, sensitivity: 'base' });
        } else if (value === 'sizeMin') {
          return this.parseSize(a.itemSize) - this.parseSize(b.itemSize);
        } else if (value === 'sizeMax') {
          return this.parseSize(b.itemSize) - this.parseSize(a.itemSize);
        }
        return 0;
      };

      folders.sort(sortFunction);
      nonFolders.sort(sortFunction);

      this.componentItems = [...folders, ...nonFolders];
      localStorage.setItem(doorSortedByKey, value);
    },

    parseSize(size) {
      if (typeof size === 'number') {
        return size;
      }

      if (typeof size !== 'string') {
        return null;
      }

      const trimmed = size.trim();

      if (trimmed === '-') {
        return -1;
      }

      if (size.includes('MB')) {
        return parseFloat(size.replace(' MB', '').trim());
      }

      const num = parseInt(trimmed, 10);
      if (!isNaN(num)) {
        return num;
      }

      return null;
    },

    updateOnlineSources(data) {
      if (data) {
        this.onlineSources = data;
        if (this.onlineSources.length === 0 ) {
          this.currentUrl = this.defaultSource[0];
          localStorage.setItem(recentDoorUrlKey, this.defaultSource[0]);
        }
      }
    },

    openAddSource() {
      $("#componentSourceOnline").modal("show");
    },

    addSourceOnline() {
      const addNameInput = document.getElementById('componentAddNameInput');
      const nameValue = addNameInput.value.trim();
      const addUrlInput = document.getElementById('componentAddUrlInput');
      const urlValue = addUrlInput.value.trim();

      const urlPattern = new RegExp('^(https?:\\/\\/)?' +
        '((([a-zA-Z0-9\\-]+\\.)+[a-zA-Z]{2,})|' +
        '((\\d{1,3}\\.){3}\\d{1,3}))' +
        '(\\:\\d+)?(\\/[-a-zA-Z0-9%_.~+]*)*' +
        '(\\?[;&a-zA-Z0-9%_.~+=-]*)?' +
        '(\\#[-a-zA-Z0-9_]*)?$', 'i');

      if (!nameValue) {
        alert('Source Name is required.');
        return;
      }

      if (!urlPattern.test(urlValue)) {
        alert('This is not a valid URL. Please try again!');
        return;
      }

      canEmbedInIframe(urlValue).then(canEmbed => {
        if (!canEmbed) {
          const message = this.$root.translated('siteBlocked');
          const action = () => { $("#componentSourceOnline").modal("show"); };
          this.$root.showNoticeModal(message, null, action);
        } else {
          const newSource = [urlValue, nameValue];
          if (!Array.isArray(this.onlineSources)) {
            this.onlineSources = [];
          }

          this.onlineSources.push(newSource);
          this.currentUrl = urlValue;

          localStorage.setItem(recentDoorUrlKey, urlValue);
          $("#componentSourceOnline").modal("hide");
          sketchup.updateComponentOnlineSources(this.onlineSources);
        }
      });
    },

    browseUrl(urlValue) {
      this.currentUrl = urlValue;
      localStorage.setItem(recentDoorUrlKey, urlValue || this.defaultSource[0]);
    },

    browseCollection(collection) {
      sketchup.browseComponentCollection(collection);
      this.selectedFolderPath = null;
      this.recentFolderPath = null;
      this.selectedType = collection;
      this.clearDeepSearch();
      this.switchMode('local');
    },

    addCollection() {
      sketchup.addComponentCollection();
      this.recentFolderPath = null;
      this.selectedFolderPath = null;
      this.selectedType = null;
    },

    handleParentClick() {
      if (this.selectedType === 'in-model') {
        sketchup.parentComponentActivePath();
      } else {
        this.parentFolder();
      }
    },

    handleItemClick(itemInfo) {
      if (itemInfo.itemType !== 'folder') {
        this.selectedModels = [itemInfo.itemName];
        sketchup.insertModel(itemInfo.itemPath, itemInfo.itemType);
      } else {
        this.browseFolder(itemInfo.itemPath, false);
        this.updateRecentChildFolder(itemInfo.itemPath);
      }
    },

    updateThumbnails() {
      const message = this.$root.translated('updateThumbnailsWaitingMessage');
      this.$root.showMessageModal(message, 'updating');
      sketchup.updateComponentThumbnails();
    },

    updateRecentChildFolder(path) {
      localStorage.setItem(recentDoorChildFolderKey, path);
    },

    updateRecentFolder(recentFolder) {
      this.recentFolderPath = recentFolder;
      this.selectedType = recentFolder;
    },

    updateFolders(newFolders) {
      if (!Array.isArray(newFolders)) return;

      // 构件页所有一级目录被删除时，清空二级目录树和当前浏览目录
      if (newFolders.length === 0) {
        this.componentFolders = [];
        this.selectedFolderPath = null;
        this.treeRootPath = null;
        this.treeRootItems = null;
        this.componentItems = [];
        this.folderEmpty = true;
        return;
      }

      newFolders.forEach(folder => {
        if (!folder.hasOwnProperty('isFolderEditing')) {
          this.$set(folder, 'isFolderEditing', false);
        }
        if (!folder.hasOwnProperty('newName')) {
          this.$set(folder, 'newName', '');
        }
      });

      this.componentFolders = newFolders;

      // 如果当前没有选中任何目录（例如首次加载或切换到该页），自动选中第一个一级目录并同步浏览
      const hasSelection = !!(this.selectedFolderPath || this.treeRootPath);
      const isCollectionType = this.selectedType === 'in-model' || this.selectedType === 'favorites' || this.selectedType === 'recent';
      if (!hasSelection && !isCollectionType && newFolders.length > 0) {
        const firstPath = newFolders[0].folderPath;
        if (firstPath) {
          this.treeRootPath = firstPath;
          this.browseFolder(firstPath, false, true);
        }
      }

      this.$nextTick(() => {
        const sortableLocal = document.getElementById('sortableLocalComponent');
        if (sortableLocal && sortableLocal._sortableInstance) {
          sortableLocal._sortableInstance.destroy();
          sortableLocal._sortableInstance = null;
        }
        this.initSortableLocal();
      });
    },

    updateItems(newItems) {
      if (newItems && newItems.length > 0) {
        newItems.forEach(item => {
          if (!item.hasOwnProperty('isItemEditing')) {
            this.$set(item, 'isItemEditing', false);
          }
          if (!item.hasOwnProperty('newName')) {
            this.$set(item, 'newName', '');
          }
        });

        this.componentItems = newItems;
        this.folderEmpty = false;
      } else {
        this.componentItems = newItems || [];
        this.folderEmpty = true;
      }
      if (this.treeRootPath == null && this.selectedFolderPath && this._browseFromLeft) this.treeRootPath = this.selectedFolderPath;
      if (this.selectedFolderPath === this.treeRootPath) {
        this.treeRootItems = this.componentItems && this.componentItems.length ? this.componentItems.slice() : [];
      }

      if (this.autoSortEnabled) {
        const sortedSaved = localStorage.getItem(doorSortedByKey) || 'nameA';
        this.sortedBy(sortedSaved);
      }

      const items = newItems || [];
      const files = items.filter(item => !(item.itemType && String(item.itemType).includes('folder')));
      const folders = items.filter(item => item.itemType && String(item.itemType).includes('folder'));
      if (files.length === 0 && folders.length > 0) {
        this.$nextTick(() => { this.browseFolder(folders[0].itemPath, false); });
      }

      handleTooltip(this);
    },

    forceRefreshThumbnails() {
      forceHideAllModals();
      const timestamp = '?t=' + Date.now();
      this.componentItems.forEach(item => {
        if (item.thumbnailPath) {
          const basePath = item.thumbnailPath.split('?')[0];
          this.$set(item, 'thumbnailPath', basePath + timestamp);
        }
      });
    },

    updateRenamedItem(result) {
      if (!result) return;
      const { oldPath, newPath, newName, thumbnailPath } = result;
      const itemInfo = this.componentItems.find(item => item.itemPath === oldPath);

      if (itemInfo) {
        this.$set(itemInfo, 'itemPath', newPath);
        this.$set(itemInfo, 'itemName', newName);
        this.$set(itemInfo, 'thumbnailPath', thumbnailPath + '?t=' + Date.now());
        this.$set(itemInfo, 'isItemEditing', false);

        const favIndex = this.favorites.indexOf(oldPath);
        if (favIndex > -1) {
          this.favorites.splice(favIndex, 1, newPath);
          sketchup.updateComponentFavorites(newPath, itemInfo.itemType);
        }
      }
    },

    addNewItem(itemData) {
      if (!itemData) return;
      if (itemData.thumbnailPath) {
        itemData.thumbnailPath = itemData.thumbnailPath + '?t=' + Date.now();
      }
      this.$set(itemData, 'isItemEditing', false);
      this.$set(itemData, 'newName', '');
      this.componentItems.push(itemData);
    },

    findInsertIndex(newItem) {
      const sortValue = this.selectedSort || 'nameA';
      const isFolder = newItem.itemType && newItem.itemType.includes('folder');

      let startIndex = 0;
      let endIndex = this.componentItems.length;

      if (isFolder) {
        endIndex = this.componentItems.findIndex(item =>
          !item.itemType || !item.itemType.includes('folder')
        );
        if (endIndex === -1) endIndex = this.componentItems.length;
      } else {
        startIndex = this.componentItems.findIndex(item =>
          !item.itemType || !item.itemType.includes('folder')
        );
        if (startIndex === -1) startIndex = this.componentItems.length;
      }

      for (let i = startIndex; i < endIndex; i++) {
        const compareItem = this.componentItems[i];
        let shouldInsertBefore = false;

        if (sortValue === 'nameA') {
          shouldInsertBefore = newItem.itemName.localeCompare(
            compareItem.itemName, undefined, { numeric: true, sensitivity: 'base' }
          ) < 0;
        } else if (sortValue === 'nameZ') {
          shouldInsertBefore = newItem.itemName.localeCompare(
            compareItem.itemName, undefined, { numeric: true, sensitivity: 'base' }
          ) > 0;
        } else if (sortValue === 'sizeMin') {
          shouldInsertBefore = this.parseSize(newItem.itemSize) < this.parseSize(compareItem.itemSize);
        } else if (sortValue === 'sizeMax') {
          shouldInsertBefore = this.parseSize(newItem.itemSize) > this.parseSize(compareItem.itemSize);
        }

        if (shouldInsertBefore) {
          return i;
        }
      }

      return endIndex;
    },

    updateTotalInModel(total) {
      const inModel = document.getElementById('componentInModel');
      if (inModel) {
        inModel.textContent = total;
      }
    },

    updateFavorites(favorites) {
      this.favorites = favorites;
      const allFavorites = document.getElementById('allComponentFavorites');
      if (allFavorites) {
        allFavorites.textContent = favorites.length;
      }
    },

    toggleFavorite(itemInfo) {
      if (itemInfo.itemType !== 'folder') {
        const index = this.favorites.indexOf(itemInfo.itemPath);
        if (index > -1) {
          this.favorites.splice(index, 1);
        } else {
          this.favorites.push(itemInfo.itemPath);
        }

        const allFavorites = document.getElementById('allComponentFavorites');
        if (allFavorites) {
          allFavorites.textContent = this.favorites.length;
        }

        sketchup.updateComponentFavorites(itemInfo.itemPath, itemInfo.itemType);
      } else {
        sketchup.addComponentCollection(itemInfo.itemPath);
      }
    },

    updateRecent(recent) {
      this.recent = recent;
      const allRecent = document.getElementById('allComponentRecent');
      if (allRecent) {
        allRecent.textContent = recent.length > 10 ? 10 : recent.length;
      }
    },

    parentFolder() {
      const recentChildFolder = localStorage.getItem(recentDoorChildFolderKey);
      sketchup.browseComponentFolder(recentChildFolder, true);
    },

    browseFolder(folderPath, parent, fromLeft) {
      this._browseFromLeft = !!fromLeft;
      sketchup.browseComponentFolder(folderPath, parent);
      this.selectedFolderPath = folderPath;
      this.recentFolderPath = null;
      this.selectedType = null;
      this.clearDeepSearch();
      this.switchMode('local');
    },

    onLeftBrowseFolder(folderPath) {
      this.treeRootPath = folderPath;
      this.browseFolder(folderPath, false, true);
    },

    selectedFolder(folderPath) {
      this.selectedFolderPath = folderPath;
    },

    showCollectionContextMenu(event, folderPath, folderName) {
      this.hideContextMenu();

      this.folderContextMenuVisible = true;

      const menuHeight = 216;
      const dialogHeight = window.innerHeight;
      const buffer = 10;

      let calculatedY = event.clientY;
      const distanceToBottom = dialogHeight - event.clientY;

      if (distanceToBottom < menuHeight + buffer) {
        calculatedY = dialogHeight - menuHeight - buffer;
      }

      this.folderContextMenuPosition.x = event.clientX;
      this.folderContextMenuPosition.y = calculatedY;

      this.actionFolderPath = folderPath;
      this.selectedFolderName = folderName;
    },

    collectionActions(action) {
      if (action === 'rename') {
        this.renameCollection(this.actionFolderPath);
      } else if (action === 'remove') {
        this.removeCollection(this.actionFolderPath);
      } else if (action === 'add_separator') {
        this.addSeparator(this.actionFolderPath);
      } else if (action === 'open_location') {
        sketchup.openFolder(this.actionFolderPath);
      }
      this.folderContextMenuVisible = false;
    },

    renameCollection(folderPath) {
      this.componentFolders.forEach(folder => {
        if (folder.isFolderEditing) {
          this.$set(folder, 'isFolderEditing', false);
        }
      });

      const folderInfo = this.componentFolders.find(folder => folder.folderPath === folderPath);
      if (folderInfo) {
        this.disableSortableLocal();

        this.$set(folderInfo, 'newName', folderInfo.customFolderName);
        this.$set(folderInfo, 'isFolderEditing', true);

        this.$nextTick(() => {
          this.$root.$emit('focus-folder-input', folderInfo.folderPath);
        });
      }
    },

    saveNewCollectionName(folderPath, oldFolderName) {
      const folderInfo = this.componentFolders.find(folder => folder.folderPath === folderPath);

      if (folderInfo && folderInfo.isFolderEditing) {
        let editedName;
        let newFolderName;
        if (folderInfo.newName) {
          newFolderName = folderInfo.newName.trim();
          if (newFolderName !== '' && newFolderName !== oldFolderName) {
            editedName = newFolderName;
          } else {
            editedName = folderInfo.customFolderName;
          }
        } else {
          editedName = folderInfo.originFolderName;
        }

        this.$set(folderInfo, 'isFolderEditing', false);
        this.enableSortableLocal();

        sketchup.renameComponentCollection(folderPath, editedName);
      }
    },

    removeCollection(folderPath) {
      // 如果当前二级目录树的根或当前选中目录就在被删除的集合下，先清空本地状态
      const base = (folderPath || '').toString().replace(/\\/g, '/').replace(/\/+$/, '');
      const selected = (this.selectedFolderPath || '').toString().replace(/\\/g, '/');
      const treeRoot = (this.treeRootPath || '').toString().replace(/\\/g, '/');

      if (base && (selected === base || selected.startsWith(base + '/') || treeRoot === base || treeRoot.startsWith(base + '/'))) {
        this.selectedFolderPath = null;
        this.treeRootPath = null;
        this.treeRootItems = null;
        this.componentItems = [];
        this.folderEmpty = true;
      }

      sketchup.removeComponentCollection(folderPath);
    },

    addSeparator(folderPath) {
      const list = document.getElementById('sortableLocalComponent');
      const items = list.getElementsByTagName('li');
      let targetItem = null;

      for (let i = 0; i < items.length; i++) {
        if (items[i].getAttribute('data-folder-path') === folderPath) {
          targetItem = items[i];
          break;
        }
      }

      if (targetItem) {
        const separatorLi = document.createElement('li');
        separatorLi.setAttribute('data-folder-path', '|-----|');
        separatorLi.className = 'li-separator';
        separatorLi.innerHTML = `
          <div class="dropdown-divider custom-dropdown-divider"></div>
          <span class="folder-name"></span>
        `;

        separatorLi.addEventListener('contextmenu', (event) => {
          event.stopPropagation();
          event.preventDefault();
          this.showSeparatorContextMenu(event);
        });

        targetItem.parentNode.insertBefore(separatorLi, targetItem.nextSibling);

        this.handleSortLocal();
      }
    },

    removeSeparator() {
      const separator = this.separatorElement;
      if (separator) {
        separator.remove();
        this.$nextTick(() => {
          this.handleSortLocal();
        });
      }
      this.separatorContextMenuVisible = false;
    },

    addSelected(folderPath) {
      const target = folderPath || this.selectedFolderPath || this.activeFolderPath;
      if (!target) {
        const message = this.$root.translated('selectFolderFirst') || 'Please select a folder first';
        this.$root.showMessageModal(message, 'info', 1500);
        return;
      }
      // 调用构件专用的“添加本地文件夹”为收藏逻辑
      sketchup.addComponentSelected(target);
    },

    showItemContextMenu(event, itemInfo) {
      this.selectedItemType = itemInfo.itemType !== 'folder' ? 'item' : 'folder';

      this.hideContextMenu();

      this.isSketchupModel = itemInfo.itemType !== 'folder';
      this.selectedItem = itemInfo;

      this.itemContextMenuVisible = true;

      this.itemContextMenuPosition = {
        x: 0,
        y: 0
      };

      this.$nextTick(() => {
        const menuElements = document.querySelectorAll('.context-menu.custom-menu');
        let menuElement = null;

        menuElements.forEach(el => {
          if (el.style.display !== 'none' && window.getComputedStyle(el).display !== 'none') {
            const hasItemContent = el.querySelector('.custom-span');
            if (hasItemContent && this.itemContextMenuVisible) {
              menuElement = el;
            }
          }
        });

        if (!menuElement) return;

        const menuRect = menuElement.getBoundingClientRect();
        const menuWidth = menuRect.width;
        const menuHeight = menuRect.height;

        const dialogWidth = window.innerWidth;
        const dialogHeight = window.innerHeight;
        const buffer = 10;

        let calculatedX = event.clientX;
        let calculatedY = event.clientY;

        const distanceToRight = dialogWidth - event.clientX;
        const distanceToBottom = dialogHeight - event.clientY;

        if (distanceToRight < menuWidth + buffer) {
          calculatedX = dialogWidth - menuWidth - buffer;
        }

        if (distanceToBottom < menuHeight + buffer) {
          calculatedY = dialogHeight - menuHeight - buffer;
        }

        if (calculatedX < buffer) {
          calculatedX = buffer;
        }
        if (calculatedY < buffer) {
          calculatedY = buffer;
        }

        this.itemContextMenuPosition.x = calculatedX;
        this.itemContextMenuPosition.y = calculatedY;
      });
    },

    getSelectedItems() {
      this.selectedItems = [this.selectedItem.itemPath];
      return this.selectedItems;
    },

    handleQuickAction(payload) {
      const { action, itemInfo } = payload || {};
      if (!itemInfo || itemInfo.itemType === 'folder') return;

      this.selectedItem = itemInfo;

      if (action === 'insert_origin') {
        this.handleItemClick(itemInfo);
      } else if (action === 'replace_instances') {
        sketchup.profileLoftComponent(itemInfo.itemPath, itemInfo.itemType);
      }
    },

    itemActions(action) {
      if (action === 'insert_origin') {
        this.handleItemClick(this.selectedItem);

      } else if (action === 'replace_instances') {
        sketchup.profileLoftComponent(this.selectedItem.itemPath, this.selectedItem.itemType);

      } else if (action === 'add_selected') {
        this.addSelected(this.selectedItem.itemPath);

      } else if (action === 'remove_recent') {
        sketchup.removeRecentModels(this.getSelectedItems());

      } else if (action === 'open') {
        sketchup.openFile(this.selectedItem.itemPath);

      } else if (action === 'save_as') {
        sketchup.saveModels(this.getSelectedItems());

      } else if (action === 'rename') {
        this.renameItem(this.selectedItem);

      } else if (action === 'delete') {
        this.getSelectedItems();
        this.confirmDeleteItems(this.selectedItem.itemType);

      } else if (action === 'purge_unused') {
        sketchup.purgeUnusedModels();

      } else if (action === 'open_location') {
        sketchup.openFileLocation(this.selectedItem.itemPath);

      } else if (action === 'find') {
        sketchup.findModelItem(this.getSelectedItems());
      }

      this.itemContextMenuVisible = false;
    },

    renameItem(itemInfo) {
      this.componentItems.forEach(item => {
        if (item.isItemEditing) {
          this.$set(item, 'isItemEditing', false);
        }
      });

      this.$set(itemInfo, 'newName', itemInfo.itemName.replace('.skp', ''));
      this.$set(itemInfo, 'isItemEditing', true);

      this.$nextTick(() => {
        this.$root.$emit('focus-item-input', itemInfo.itemName);
      });
    },

    cancelRenameItem(itemPath, oldItemName) {
      const itemInfo = this.componentItems.find(item => item.itemPath === itemPath);
      if (itemInfo && itemInfo.isItemEditing) {
        this.$set(itemInfo, 'itemName', oldItemName);
        this.$set(itemInfo, 'isItemEditing', false);
      }
    },

    saveNewItemName(itemPath, oldItemName) {
      const itemInfo = this.componentItems.find(item => item.itemPath === itemPath);

      if (itemInfo && itemInfo.isItemEditing) {
        if (itemInfo.newName) {
          const newItemName = itemInfo.newName.trim();

          if (!this.validateFileName(newItemName, oldItemName)) {
            return;
          }

          this.nameExists = this.componentItems.some(item =>
            item.itemName.toLowerCase().replace('.skp', '') === newItemName.toLowerCase() &&
            item.itemPath !== itemPath
          );

          if (this.nameExists) {
            if (!itemInfo.showingError) {
              this.$set(itemInfo, 'showingError', true);
              const message = this.$root.translated('duplicateNameExistsAlert');
              this.$root.showMessageModal(message, 'error', 1000);
              setTimeout(() => {
                this.$set(itemInfo, 'showingError', false);
                this.$root.$emit('focus-item-input', oldItemName);
              }, 1200);
            }
            return;
          }

          if (newItemName !== '' && newItemName !== oldItemName) {
            const item = [itemInfo, oldItemName, newItemName];
            sketchup.renameComponentItem(item);
          }
        }

        this.$set(itemInfo, 'isItemEditing', false);
      }
    },

    confirmDeleteItems(type) {
      let message;
      let action1 = () => null;
      let action2;

      if (type === 'skp') {
        message = this.translated('confirmDeleteMessage');
        action2 = () => sketchup.deleteComponentItems(this.selectedItems);
      } else if (type === 'folder') {
        message = this.translated('confirmDeleteFolderMessage');
        action2 = () => sketchup.deleteFolders(this.selectedItems);
      } else {
        message = this.translated('confirmDeleteMessage');
        action2 = () => sketchup.deleteModelInModel(this.selectedItems);
      }

      this.$root.showNoticeModal(message, action1, action2);
    },

    updateDeleteItems(itemPaths) {
      itemPaths.forEach(itemPath => {
        const index = this.componentItems.findIndex(item => item.itemPath === itemPath);
        if (index > -1) {
          this.componentItems.splice(index, 1);
        }

        const favIndex = this.favorites.indexOf(itemPath);
        if (favIndex > -1) {
          this.favorites.splice(favIndex, 1);
        }
      });

      const allFavorites = document.getElementById('allComponentFavorites');
      if (allFavorites) {
        allFavorites.textContent = this.favorites.length;
      }
    },

    showOnlineContextMenu(event, source) {
      this.hideContextMenu();

      this.selectedOnlineName = source[1];
      this.selectedOnlineUrl = source[0];

      this.onlineContextMenuVisible = true;

      this.$nextTick(() => {
        const menuElements = document.querySelectorAll('.context-menu.custom-menu');
        let menuElement = null;

        for (let i = menuElements.length - 1; i >= 0; i--) {
          if (menuElements[i].style.display !== 'none' && this.onlineContextMenuVisible) {
            menuElement = menuElements[i];
            break;
          }
        }

        if (!menuElement) return;

        const menuRect = menuElement.getBoundingClientRect();
        const menuWidth = menuRect.width;
        const menuHeight = menuRect.height;

        const dialogWidth = window.innerWidth;
        const dialogHeight = window.innerHeight;
        const buffer = 10;

        let calculatedX = event.clientX;
        let calculatedY = event.clientY;

        const distanceToRight = dialogWidth - event.clientX;
        const distanceToBottom = dialogHeight - event.clientY;

        if (distanceToRight < menuWidth + buffer) {
          calculatedX = dialogWidth - menuWidth - buffer;
        }

        if (distanceToBottom < menuHeight + buffer) {
          calculatedY = dialogHeight - menuHeight - buffer;
        }

        this.onlineContextMenuPosition.x = calculatedX;
        this.onlineContextMenuPosition.y = calculatedY;
      });
    },

    onlineActions(action) {
      if (action === 'rename') {
        this.renameOnlineSource(this.selectedOnlineUrl, this.selectedOnlineName);
      } else if (action === 'delete') {
        this.deleteOnlineSource(this.selectedOnlineUrl);
      }
      this.onlineContextMenuVisible = false;
    },

    renameOnlineSource(url, name) {
      const source = this.onlineSources.find(s => s[0] === url);
      if (source) {
        this.$set(source, 'newName', name);
        this.$set(source, 'isOnlineEditing', true);

        this.$nextTick(() => {
          if (this.$refs.onlineContainer) {
            this.$refs.onlineContainer.focusInput(name);
          }
        });
      }
    },

    saveNewOnlineSourceName(url, oldName) {
      const source = this.onlineSources.find(s => s[0] === url);
      if (source) {
        let newName = source.newName ? source.newName.trim() : oldName;
        if (!newName) newName = oldName;

        source[1] = newName;
        this.$set(source, 'isOnlineEditing', false);
        sketchup.updateComponentOnlineSources(this.onlineSources);
      }
    },

    deleteOnlineSource(url) {
      this.onlineSources = this.onlineSources.filter(s => s[0] !== url);
      if (this.currentUrl === url) {
        this.currentUrl = this.defaultSource[0];
        localStorage.setItem(recentDoorUrlKey, this.defaultSource[0]);
      }
      sketchup.updateComponentOnlineSources(this.onlineSources);
    },

    showSeparatorContextMenu(event) {
      this.hideContextMenu();

      this.separatorContextMenuVisible = true;

      this.separatorElement = event.currentTarget.closest('li');

      const menuHeight = 60;
      const dialogHeight = window.innerHeight;
      const buffer = 10;

      let calculatedY = event.clientY;
      const distanceToBottom = dialogHeight - event.clientY;

      if (distanceToBottom < menuHeight + buffer) {
        calculatedY = dialogHeight - menuHeight - buffer;
      }

      this.separatorContextMenuPosition.x = event.clientX;
      this.separatorContextMenuPosition.y = calculatedY;
    },

    showContentContextMenu(event) {
      if (this.selectedType === 'favorites' || this.selectedType === 'recent') {
        return;
      }

      this.hideContextMenu();

      this.contentContextMenuVisible = true;

      this.$nextTick(() => {
        const menuElements = document.querySelectorAll('.context-menu.custom-menu');
        let menuElement = null;

        for (let i = menuElements.length - 1; i >= 0; i--) {
          if (menuElements[i].style.display !== 'none' && this.contentContextMenuVisible) {
            menuElement = menuElements[i];
            break;
          }
        }

        if (!menuElement) return;

        const menuRect = menuElement.getBoundingClientRect();
        const menuWidth = menuRect.width;
        const menuHeight = menuRect.height;

        const dialogWidth = window.innerWidth;
        const dialogHeight = window.innerHeight;
        const buffer = 10;

        let calculatedX = event.clientX;
        let calculatedY = event.clientY;

        const distanceToRight = dialogWidth - event.clientX;
        const distanceToBottom = dialogHeight - event.clientY;

        if (distanceToRight < menuWidth + buffer) {
          calculatedX = dialogWidth - menuWidth - buffer;
        }

        if (distanceToBottom < menuHeight + buffer) {
          calculatedY = dialogHeight - menuHeight - buffer;
        }

        this.contentContextMenuPosition.x = calculatedX;
        this.contentContextMenuPosition.y = calculatedY;
      });
    },

    contentActions(action) {
      if (action === 'add_selected') {
        this.addSelected(this.selectedFolderPath);
      } else if (action === 'purge_unused') {
        sketchup.purgeUnusedModels();
      }
      this.contentContextMenuVisible = false;
    },

    handleSortLocal() {
      const list = document.getElementById('sortableLocalComponent');
      const items = list.getElementsByTagName('li');
      const newOrder = [];

      for (let i = 0; i < items.length; i++) {
        const folderPath = items[i].getAttribute('data-folder-path');
        const element = items[i].querySelector('.folder-name');
        const folderName = (element && element.textContent) || '';

        if (folderPath) {
          newOrder.push([folderPath, folderName]);
        }
      }
      sketchup.updateComponentFolderOrder(JSON.stringify(newOrder));
    },

    handleSortOnline() {
      const list = document.getElementById('sortableOnlineComponent');
      const items = list.getElementsByTagName('button');
      const newOrder = [];

      if (this.defaultSource.length > 0) {
      }

      for (let i = 0; i < items.length; i++) {
        const url = items[i].getAttribute('data-url');
        const name = items[i].textContent.trim();
        if (url) {
          newOrder.push([url, name]);
        }
      }

      this.onlineSources = newOrder;
      sketchup.updateComponentOnlineSources(this.onlineSources);
    },

    updateActive(root, path) {
      this.activeModel = root;
      if (path) {
        this.activeModelPath = path;
      } else {
        this.activeModelPath = [];
      }
    },

    loadDetailsState() {
      this.showDetails = true;
    },

    saveDetailsState(_newValue) {
      this.showDetails = true;
    },

    loadShowAllState() {
      const showAllState = localStorage.getItem(doorShowAllStateKey);
      this.showAllModels = showAllState !== 'false';
    },

    updateShowAll(value) {
      this.showAllModels = value;
      localStorage.setItem(doorShowAllStateKey, this.showAllModels);
      handleTooltip(this);
    },

    toggleShowAllModels() {
      if (!this.showAllModels) {
        if (this.firstShowAllModel) {
          const message = this.$root.translated('showAllModelsWarning');
          const action1 = () => this.changeShowAll('false');
          const action2 = () => this.changeShowAll('true');
          this.$root.showNoticeModal(message, action1, action2);
          this.firstShowAllModel = false;
        } else {
          this.changeShowAll('true');
        }
      } else {
        this.changeShowAll('false');
      }
    },

    changeShowAll(value) {
      if (value === 'true') {
        this.showAllModels = true;
        localStorage.setItem(doorShowAllStateKey, 'true');
      } else if (value === 'false') {
        this.showAllModels = false;
        localStorage.setItem(doorShowAllStateKey, 'false');
      }

      sketchup.showAllComponents(this.showAllModels);
    },

    onEnterKey(folderPath, folderName) {
      this.saveNewCollectionName(folderPath, folderName);
    },

    onBlur(folderPath, folderName) {
      this.$nextTick(() => {
        this.saveNewCollectionName(folderPath, folderName);
      });
    },

    cancelRename(folderPath) {
      const folderInfo = this.componentFolders.find(folder => folder.folderPath === folderPath);
      if (folderInfo && folderInfo.isFolderEditing) {
        this.$set(folderInfo, 'newName', folderInfo.customFolderName);
        this.$set(folderInfo, 'isFolderEditing', false);
        this.enableSortableLocal();
      }
    },

    goToRoot() {
      sketchup.parentComponentActivePath('root');
    },

    goToParent(index) {
      sketchup.parentComponentActivePath(this.activeModelPath[index]);
    },

    updateSelected(value) {
      this.selectedModels = value;
    },

    updateActiveFolder(value) {
      this.activeFolderPath = value;
    },

    updateIsDrive(value) {
      this.isDrive = value;
    },

    handleDeepSearch() {
      if (this.isDrive) {
        const message = this.$root.translated('deepSearchDriveNotSupported');
        this.$root.showMessageModal(message, 'info', 2000);
        return;
      }

      if (!this.enableDeepSearch) return;
      if (!this.searchQuery || !this.searchQuery.trim()) return;
      if (!this.activeFolderPath) {
        const message = this.$root.translated('selectFolderFirst') || 'Please select a folder first';
        this.$root.showMessageModal(message, 'info', 1500);
        return;
      }

      if (this.selectedType === 'in-model' || this.selectedType === 'favorites' || this.selectedType === 'recent') {
        return;
      }

      const message = this.$root.translated('deepSearching');
      this.$root.showMessageModal(message, 'deepSearching', 'wait');

      setTimeout(() => {
        this.performDeepSearch();
      }, 500);
    },

    performDeepSearch() {
      sketchup.deepSearchComponent(this.searchQuery.trim(), this.activeFolderPath);
    },

    updateDeepSearchResults(items) {
      this.deepSearchResults = items || [];

      if (this.deepSearchResults.length === 0) {
        const message1 = this.$root.translated('noDeepSearchResults');
        const message2 = this.$root.translated('searchWithinSubfolders');
        const message = `${message1}<br><br>${message2}`;
        this.$root.showNoticeModal(message);
      } else {
        forceHideAllModals();
      }

      this.isDeepSearching = false;
    },

    setDeepSearchLoading(isLoading) {
      this.isDeepSearching = isLoading;
    },

    clearDeepSearch() {
      this.deepSearchResults = [];
      this.isDeepSearching = false;
    },
  },

  template: /*html*/`
    <div
      :class="['d-flex', 'library-container', sidebarOpen ? 'sidebar-open' : 'sidebar-closed']"
      id="component-app"
    >
      <div
        class="sidebar-wrapper"
        :style="{ width: sidebarOpen ? (sidebarWidth + 'px') : '0' }"
      >
        <side-bar
          type="component"
          :isOnline="isOnline"
          :selectedType="selectedType"
          :folders="componentFolders"
          :sortOrderFolders="sortOrderFolders"
          :recentFolderPath="recentFolderPath"
          :selectedFolderPath="selectedFolderPath"
          :treeRootPath="treeRootPath || ''"
          @switch-mode="switchMode"
          @browse-collection="browseCollection"
          @sort-folders="sortFolders"
          @add-collection="addCollection"
          @browse-folder="onLeftBrowseFolder"
          @folder-context-menu="(payload) => showCollectionContextMenu(payload.event, payload.folderPath, payload.folderName)"
          @separator-context-menu="showSeparatorContextMenu"
          @hide-context-menu="hideContextMenu"
          @folder-enter="(payload) => onEnterKey(payload.folderPath, payload.folderName)"
          @folder-blur="(payload) => onBlur(payload.folderPath, payload.folderName)"
          @folder-esc="(payload) => cancelRename(payload.folderPath)"
        ></side-bar>
        <div
          v-show="sidebarOpen"
          class="resize-handle"
          @mousedown.prevent="startResizeSidebar"
          title="拖拽调节宽度"
        ></div>
      </div>

      <div
        v-if="!isOnline && subfolderColumnVisible"
        class="subfolder-column-wrapper"
        :style="{ width: subfolderColumnWidth + 'px' }"
      >
        <subfolder-column
          type="component"
          :visible="true"
          :items="subfolderTreeItems"
          :selected-folder-path="selectedFolderPath"
          @browse-subfolder="(path) => browseFolder(path, false)"
        ></subfolder-column>
        <div
          class="subfolder-resize-handle"
          @mousedown.prevent="startResizeSubfolderColumn"
          title="拖拽调节宽度"
        ></div>
      </div>

      <online-container
        ref="onlineContainer"
        type="model"
        :isOnline="isOnline"
        :defaultSource="defaultSource"
        :onlineSources="onlineSources"
        :currentUrl="currentUrl"
        @browse-url="browseUrl"
        @show-online-context-menu="(payload) => showOnlineContextMenu(payload.event, payload.source)"
        @save-online-source-name="(payload) => saveNewOnlineSourceName(payload.url, payload.oldName)"
        @open-add-source="openAddSource"
      ></online-container>

      <div v-if="!isOnline" class="local-container flex-grow-1 subfolder-main-content">
        <local-panel
          type="component"
          :sidebarOpen="sidebarOpen"
          :isSmallWindow="isSmallWindow"
          :selectedType="selectedType"
          :isDrive="isDrive"
          :activeModel="activeModel"
          :showAllModels="showAllModels"
          :isMediumWindow="isMediumWindow"
          :viewMode="viewMode"
          :showDetails="showDetails"
          :currentView="currentView"
          :selectedSort="selectedSort"
          :activeFolderPath="activeFolderPath || ''"
          :selectedFolderPath="selectedFolderPath || ''"
          :treeRootPath="treeRootPath || ''"
          @handle-parent-click="handleParentClick"
          @browse-folder-path="(path) => browseFolder(path, false)"
          @add-selected="addSelected(selectedFolderPath)"
          @details-change="saveDetailsState"
          @change-view="changeView"
          @update-thumbnails="updateThumbnails"
          @sort-by="sortedBy"
        ></local-panel>

        <component-content
          :isOnline="isOnline"
          :selectedType="selectedType"
          :showAllModels="showAllModels"
          :activeModelPath="activeModelPath"
          :viewMode="viewMode"
          :currentStyle="currentStyle"
          :folderEmpty="folderEmpty"
          :showDetails="showDetails"
          :sidebarOpen="sidebarOpen"
          :isSmallWindow="isSmallWindow"
          :isMediumWindow="isMediumWindow"
          :filteredItems="filteredItems"
          :selectedModels="selectedModels"
          :favorites="favorites"
          :dynamicIconPath="dynamicIconPath"
          :liveIconPath="liveIconPath"
          @content-context-menu="showContentContextMenu"
          @item-context-menu="(payload) => showItemContextMenu(payload.event, payload.itemInfo)"
          @item-click="handleItemClick"
          @update-selected="updateSelected"
          @update-active-folder="updateActiveFolder"
          @toggle-show-all-models="toggleShowAllModels"
          @toggle-favorite="toggleFavorite"
          @quick-action="handleQuickAction"
          @hide-context-menu="hideContextMenu"
          @save-new-item-name="(payload) => saveNewItemName(payload.itemPath, payload.itemName)"
          @cancel-rename-item="(payload) => cancelRenameItem(payload.itemPath, payload.itemName)"
          @go-to-root="goToRoot"
          @go-to-parent="goToParent"
        ></component-content>
      </div>

      <door-context-menus
        :showDetails="showDetails"
        :folderContextMenuVisible="folderContextMenuVisible"
        :folderContextMenuPosition="folderContextMenuPosition"
        :separatorContextMenuVisible="separatorContextMenuVisible"
        :separatorContextMenuPosition="separatorContextMenuPosition"
        :contentContextMenuVisible="contentContextMenuVisible"
        :contentContextMenuPosition="contentContextMenuPosition"
        :selectedType="selectedType"
        :itemContextMenuVisible="itemContextMenuVisible"
        :itemContextMenuPosition="itemContextMenuPosition"
        :isSketchupModel="isSketchupModel"
        :selectedItemType="selectedItemType"
        :sidebarOpen="sidebarOpen"
        :isMediumWindow="isMediumWindow"
        :onlineContextMenuVisible="onlineContextMenuVisible"
        :onlineContextMenuPosition="onlineContextMenuPosition"
        @collection-actions="collectionActions"
        @content-actions="contentActions"
        @item-actions="itemActions"
        @online-actions="onlineActions"
        @remove-separator="removeSeparator"
      ></door-context-menus>

      <user-options-modal
        type="material"
        :userOptionsMessage="userOptionsMessage"
        :userOptions="userOptions"
      ></user-options-modal>

      <add-source-modal
        type="material"
        @add-source="addSourceOnline"
      ></add-source-modal>
    </div>
  `
};

