Skip to content

Commit

Permalink
feat: ✨ Add Folder view to Sidebar
Browse files Browse the repository at this point in the history
fix #134
  • Loading branch information
phibr0 committed Dec 28, 2021
1 parent 407dcc0 commit 919dc44
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const DEFAULT_SETTINGS: ObsidianGitSettings = {
customMessageOnAutoBackup: false,
autoBackupAfterFileChange: false,
mergeOnPull: true,
treeStructure: false,
};

export const GIT_VIEW_CONFIG = {
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface ObsidianGitSettings {
customMessageOnAutoBackup: boolean;
autoBackupAfterFileChange: boolean;
mergeOnPull: boolean;
treeStructure: boolean;
}

export interface Author {
Expand Down
4 changes: 3 additions & 1 deletion src/ui/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ export default function addIcons(): void {
addFeatherIcon('alert-circle');
addFeatherIcon('alert-triangle');
addFeatherIcon('git-commit');
addFeatherIcon('edit')
addFeatherIcon('edit');
addFeatherIcon('folder');
addFeatherIcon('list');
}
98 changes: 98 additions & 0 deletions src/ui/sidebar/components/treeComponent.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script lang="ts">
import FileComponent from "./fileComponent.svelte";
import ObsidianGit from "src/main";
import GitView from "../sidebarView";
import StagedFileComponent from "./stagedFileComponent.svelte";
import { slide } from "svelte/transition";
export let hierarchy: any;
export let plugin: ObsidianGit;
export let view: GitView;
export let staged: boolean;
export let topLevel = false;
let open: boolean[] = [];
</script>

<main class:topLevel>
{#each Object.keys(hierarchy) as entity, index}
<!-- this will break if there is a file called "_file_" without extension -->
{#if hierarchy[entity]._file_}
<div class="file-view">
{#if staged}
<StagedFileComponent
change={hierarchy[entity]._file_}
manager={plugin.gitManager}
{view}
/>
{:else}
<FileComponent
change={hierarchy[entity]._file_}
manager={plugin.gitManager}
{view}
workspace={plugin.app.workspace}
/>
{/if}
</div>
{:else}
<div
class="opener tree-item-self is-clickable"
class:open={open[index]}
on:click={() => (open[index] = !open[index])}
>
<div>
<div class="tree-item-icon collapse-icon" style="">
<svg
viewBox="0 0 100 100"
class="right-triangle"
width="8"
height="8"
><path
fill="currentColor"
stroke="currentColor"
d="M94.9,20.8c-1.4-2.5-4.1-4.1-7.1-4.1H12.2c-3,0-5.7,1.6-7.1,4.1c-1.3,2.4-1.2,5.2,0.2,7.6L43.1,88c1.5,2.3,4,3.7,6.9,3.7 s5.4-1.4,6.9-3.7l37.8-59.6C96.1,26,96.2,23.2,94.9,20.8L94.9,20.8z"
/></svg
>
</div>
<span>{entity}</span>
</div>
</div>
{#if open[index]}
<div class="file-view" transition:slide|local={{ duration: 75 }}>
<svelte:self hierarchy={hierarchy[entity]} {plugin} {view} {staged} />
</div>
{/if}
{/if}
{/each}
</main>

<style lang="scss">
main:not(.topLevel) {
margin-left: 5px;
}
.opener {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 4px;
.collapse-icon::after {
content: "\00a0";
}
div {
display: flex;
}
svg {
transform: rotate(-90deg);
}
&.open svg {
transform: rotate(0);
}
span {
font-size: 0.8rem;
}
}
.file-view {
margin-left: 5px
}
</style>
90 changes: 76 additions & 14 deletions src/ui/sidebar/gitView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,38 @@
import { slide } from "svelte/transition";
import FileComponent from "./components/fileComponent.svelte";
import StagedFileComponent from "./components/stagedFileComponent.svelte";
import TreeComponent from "./components/treeComponent.svelte";
import GitView from "./sidebarView";
export let plugin: ObsidianGit;
export let view: GitView;
let commitMessage = plugin.settings.commitMessage;
let buttons: HTMLElement[] = [];
let status: Status | null;
let changeHierarchy: any;
let stagedHierarchy: any;
let changesOpen = true;
let stagedOpen = true;
let loading = true;
const debRefresh = debounce(() => refresh(), 300000);
//Refresh every ten minutes
const interval = window.setInterval(refresh, 600000);
let showTree = plugin.settings.treeStructure;
let layoutBtn: HTMLElement;
$: {
if (layoutBtn) {
layoutBtn.empty();
setIcon(layoutBtn, showTree ? "feather-list" : "feather-folder", 16);
}
}
let event: EventRef;
//This should go in the onMount callback, for some reason it doesn't fire though
//setImmediate's callback will execute after the current event loop finishes.
plugin.app.workspace.onLayoutReady(() =>
setImmediate(() => {
buttons.forEach((btn) => setIcon(btn, btn.getAttr("data-icon"), 16));
setIcon(layoutBtn, showTree ? "feather-list" : "feather-folder", 16);
refresh();
Expand Down Expand Up @@ -57,6 +69,29 @@
loading = true;
promise.then((s) => {
status = s;
// https://stackoverflow.com/a/26652662
changeHierarchy = s.changed.reduce(function (hier: any, file) {
var x = hier;
file.path.split("/").forEach(function (item) {
if (!x[item]) {
x[item] = {};
}
x = x[item];
});
x._file_ = file;
return hier;
}, {});
stagedHierarchy = s.staged.reduce(function (hier: any, file) {
var x = hier;
file.path.split("/").forEach(function (item) {
if (!x[item]) {
x[item] = {};
}
x = x[item];
});
x._file_ = file;
return hier;
}, {});
loading = false;
});
}
Expand Down Expand Up @@ -133,14 +168,21 @@
bind:this={buttons[4]}
on:click={pull}
/>
<div
id="layoutChange"
class="nav-action-button"
aria-label="Change Layout"
bind:this={layoutBtn}
on:click={() => (showTree = !showTree)}
/>
</div>
<div
id="refresh"
class="nav-action-button"
class:loading
data-icon="feather-refresh-cw"
aria-label="Refresh"
bind:this={buttons[5]}
bind:this={buttons[6]}
on:click={refresh}
/>
<div class="search-input-container">
Expand Down Expand Up @@ -188,14 +230,24 @@
</div>
{#if stagedOpen}
<div class="file-view" transition:slide|local={{ duration: 150 }}>
{#each status.staged as stagedFile}
<StagedFileComponent
change={stagedFile}
{#if showTree}
<TreeComponent
hierarchy={stagedHierarchy}
{plugin}
{view}
manager={plugin.gitManager}
on:git-refresh={refresh}
staged={true}
topLevel={true}
/>
{/each}
{:else}
{#each status.staged as stagedFile}
<StagedFileComponent
change={stagedFile}
{view}
manager={plugin.gitManager}
on:git-refresh={refresh}
/>
{/each}
{/if}
</div>
{/if}
</div>
Expand Down Expand Up @@ -225,15 +277,25 @@
</div>
{#if changesOpen}
<div class="file-view" transition:slide|local={{ duration: 150 }}>
{#each status.changed as change}
<FileComponent
{change}
{#if showTree}
<TreeComponent
hierarchy={changeHierarchy}
{plugin}
{view}
manager={plugin.gitManager}
workspace={plugin.app.workspace}
on:git-refresh={refresh}
staged={false}
topLevel={true}
/>
{/each}
{:else}
{#each status.changed as change}
<FileComponent
{change}
{view}
manager={plugin.gitManager}
workspace={plugin.app.workspace}
on:git-refresh={refresh}
/>
{/each}
{/if}
</div>
{/if}
</div>
Expand Down

0 comments on commit 919dc44

Please sign in to comment.