forked from Shiloh/githaven
72eedfb915
Feel free to close this if there isn't interest. The tree view looks amazing, and all of our users are really enjoying it (major kudos to developers!), but only IF I tell them it exists! Essentially, the file tree view as it is effectively undiscoverable. This PR changes the default state for the tree view to open, which should significantly help with discoverability. An alternative could be to reserve more horizontal space, as a typical accordion panel would look (eg. VS Code), eg. ![image](https://github.com/go-gitea/gitea/assets/12700993/505ea40c-42b1-4111-b306-48e51e8e2130)
140 lines
4.7 KiB
Vue
140 lines
4.7 KiB
Vue
<template>
|
|
<div v-if="store.fileTreeIsVisible" class="gt-mr-3 gt-mt-3 diff-detail-box">
|
|
<!-- only render the tree if we're visible. in many cases this is something that doesn't change very often -->
|
|
<div class="ui list">
|
|
<DiffFileTreeItem v-for="item in fileTree" :key="item.name" :item="item"/>
|
|
</div>
|
|
<div v-if="store.isIncomplete" class="gt-pt-2">
|
|
<a :class="['ui', 'basic', 'tiny', 'button', store.isLoadingNewData ? 'disabled' : '']" @click.stop="loadMoreData">{{ store.showMoreMessage }}</a>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import DiffFileTreeItem from './DiffFileTreeItem.vue';
|
|
import {loadMoreFiles} from '../features/repo-diff.js';
|
|
import {toggleElem} from '../utils/dom.js';
|
|
import {diffTreeStore} from '../modules/stores.js';
|
|
import {setFileFolding} from '../features/file-fold.js';
|
|
|
|
const LOCAL_STORAGE_KEY = 'diff_file_tree_visible';
|
|
|
|
export default {
|
|
components: {DiffFileTreeItem},
|
|
data: () => {
|
|
return {store: diffTreeStore()};
|
|
},
|
|
computed: {
|
|
fileTree() {
|
|
const result = [];
|
|
for (const file of this.store.files) {
|
|
// Split file into directories
|
|
const splits = file.Name.split('/');
|
|
let index = 0;
|
|
let parent = null;
|
|
let isFile = false;
|
|
for (const split of splits) {
|
|
index += 1;
|
|
// reached the end
|
|
if (index === splits.length) {
|
|
isFile = true;
|
|
}
|
|
let newParent = {
|
|
name: split,
|
|
children: [],
|
|
isFile
|
|
};
|
|
|
|
if (isFile === true) {
|
|
newParent.file = file;
|
|
}
|
|
|
|
if (parent) {
|
|
// check if the folder already exists
|
|
const existingFolder = parent.children.find(
|
|
(x) => x.name === split
|
|
);
|
|
if (existingFolder) {
|
|
newParent = existingFolder;
|
|
} else {
|
|
parent.children.push(newParent);
|
|
}
|
|
} else {
|
|
const existingFolder = result.find((x) => x.name === split);
|
|
if (existingFolder) {
|
|
newParent = existingFolder;
|
|
} else {
|
|
result.push(newParent);
|
|
}
|
|
}
|
|
parent = newParent;
|
|
}
|
|
}
|
|
const mergeChildIfOnlyOneDir = (entries) => {
|
|
for (const entry of entries) {
|
|
if (entry.children) {
|
|
mergeChildIfOnlyOneDir(entry.children);
|
|
}
|
|
if (entry.children.length === 1 && entry.children[0].isFile === false) {
|
|
// Merge it to the parent
|
|
entry.name = `${entry.name}/${entry.children[0].name}`;
|
|
entry.children = entry.children[0].children;
|
|
}
|
|
}
|
|
};
|
|
// Merge folders with just a folder as children in order to
|
|
// reduce the depth of our tree.
|
|
mergeChildIfOnlyOneDir(result);
|
|
return result;
|
|
}
|
|
},
|
|
mounted() {
|
|
// Default to true if unset
|
|
this.store.fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) !== 'false';
|
|
document.querySelector('.diff-toggle-file-tree-button').addEventListener('click', this.toggleVisibility);
|
|
|
|
this.hashChangeListener = () => {
|
|
this.store.selectedItem = window.location.hash;
|
|
this.expandSelectedFile();
|
|
};
|
|
this.hashChangeListener();
|
|
window.addEventListener('hashchange', this.hashChangeListener);
|
|
},
|
|
unmounted() {
|
|
document.querySelector('.diff-toggle-file-tree-button').removeEventListener('click', this.toggleVisibility);
|
|
window.removeEventListener('hashchange', this.hashChangeListener);
|
|
},
|
|
methods: {
|
|
expandSelectedFile() {
|
|
// expand file if the selected file is folded
|
|
if (this.store.selectedItem) {
|
|
const box = document.querySelector(this.store.selectedItem);
|
|
const folded = box?.getAttribute('data-folded') === 'true';
|
|
if (folded) setFileFolding(box, box.querySelector('.fold-file'), false);
|
|
}
|
|
},
|
|
toggleVisibility() {
|
|
this.updateVisibility(!this.store.fileTreeIsVisible);
|
|
},
|
|
updateVisibility(visible) {
|
|
this.store.fileTreeIsVisible = visible;
|
|
localStorage.setItem(LOCAL_STORAGE_KEY, this.store.fileTreeIsVisible);
|
|
this.updateState(this.store.fileTreeIsVisible);
|
|
},
|
|
updateState(visible) {
|
|
const btn = document.querySelector('.diff-toggle-file-tree-button');
|
|
const [toShow, toHide] = btn.querySelectorAll('.icon');
|
|
const tree = document.getElementById('diff-file-tree');
|
|
const newTooltip = btn.getAttribute(visible ? 'data-hide-text' : 'data-show-text');
|
|
btn.setAttribute('data-tooltip-content', newTooltip);
|
|
toggleElem(tree, visible);
|
|
toggleElem(toShow, !visible);
|
|
toggleElem(toHide, visible);
|
|
},
|
|
loadMoreData() {
|
|
loadMoreFiles(this.store.linkLoadMore);
|
|
},
|
|
},
|
|
};
|
|
</script>
|