Add left links sidebar to IDE

[ci skip]
This commit is contained in:
Phil Hughes 2018-04-13 15:35:03 +01:00
parent d8dd75ca77
commit bdc437fc76
No known key found for this signature in database
GPG key ID: 32245528C52E0F9F
12 changed files with 233 additions and 155 deletions

View file

@ -0,0 +1,109 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import ExternalLinks from './ide_external_links.vue';
import { ActivityBarViews } from '../stores/state';
export default {
components: {
Icon,
ExternalLinks,
},
computed: {
...mapGetters(['currentProject']),
...mapState(['currentActivityView']),
},
methods: {
...mapActions(['updateActivityBarView']),
},
ActivityBarViews,
};
</script>
<template>
<nav class="ide-activity-bar">
<ul class="list-unstyled">
<li>
<external-links
class="ide-activity-bar-link"
:project-url="currentProject.web_url"
/>
</li>
<li>
<a
href="#"
class="ide-sidebar-link ide-activity-bar-link"
:class="{
active: currentActivityView === $options.ActivityBarViews.edit
}"
@click.prevent="updateActivityBarView($options.ActivityBarViews.edit)"
>
<icon
:size="16"
name="code"
/>
</a>
</li>
<li>
<a
href="#"
class="ide-sidebar-link ide-activity-bar-link"
:class="{
active: currentActivityView === $options.ActivityBarViews.commit
}"
@click.prevent="updateActivityBarView($options.ActivityBarViews.commit)"
>
<icon
:size="16"
name="commit"
/>
</a>
</li>
</ul>
</nav>
</template>
<style>
.ide-activity-bar {
position: relative;
flex: 0 0 60px;
z-index: 2;
}
.ide-activity-bar-link {
position: relative;
height: 55px;
margin: 2.5px 0;
color: #707070;
border-top: 1px solid transparent;
border-bottom: 1px solid transparent;
}
.ide-activity-bar-link svg {
margin: 0 auto;
fill: currentColor;
}
.ide-activity-bar-link.active {
color: #4b4ba3;
background-color: #fff;
border-top: 1px solid #eaeaea;
border-bottom: 1px solid #eaeaea;
box-shadow: inset 3px 0 #4b4ba3;
}
a.ide-sidebar-link.ide-activity-bar-link.active::after {
content: '';
position: absolute;
right: -1px;
top: 0;
bottom: 0;
width: 1px;
background: #fff;
}
.ide-activity-bar-link:hover {
color: #4b4ba3;
background-color: #fff;
}
</style>

View file

@ -100,9 +100,9 @@ export default {
</div>
</template>
</div>
<ide-contextbar
<!-- <ide-contextbar
:no-changes-state-svg-path="noChangesStateSvgPath"
:committed-state-svg-path="committedStateSvgPath"
/>
/> -->
</div>
</template>

View file

@ -20,24 +20,15 @@ export default {
</script>
<template>
<nav
class="ide-external-links"
<a
:href="goBackUrl"
class="ide-sidebar-link"
:aria-label="s__('IDE|Go back')"
v-once
>
<p>
<a
:href="goBackUrl"
class="ide-sidebar-link"
>
<icon
:size="16"
class="append-right-8"
name="go-back"
/>
<span class="ide-external-links-text">
{{ s__('Go back') }}
</span>
</a>
</p>
</nav>
<icon
:size="16"
name="go-back"
/>
</a>
</template>

View file

@ -1,15 +1,9 @@
<script>
import ProjectAvatarImage from '~/vue_shared/components/project_avatar/image.vue';
import Identicon from '../../vue_shared/components/identicon.vue';
import BranchesTree from './ide_project_branches_tree.vue';
import ExternalLinks from './ide_external_links.vue';
export default {
components: {
BranchesTree,
ExternalLinks,
ProjectAvatarImage,
Identicon,
},
props: {
project: {
@ -22,37 +16,6 @@ export default {
<template>
<div class="projects-sidebar">
<div class="context-header">
<a
:title="project.name"
:href="project.web_url"
>
<div
v-if="project.avatar_url"
class="avatar-container s40 project-avatar"
>
<project-avatar-image
class="avatar-container project-avatar"
:link-href="project.path"
:img-src="project.avatar_url"
:img-alt="project.name"
:img-size="40"
/>
</div>
<identicon
v-else
size-class="s40"
:entity-id="project.id"
:entity-name="project.name"
/>
<div class="sidebar-context-title">
{{ project.name }}
</div>
</a>
</div>
<external-links
:project-url="project.web_url"
/>
<div class="multi-file-commit-panel-inner-scroll">
<branches-tree
v-for="branch in project.branches"

View file

@ -1,36 +1,41 @@
<script>
import { mapState, mapGetters } from 'vuex';
import icon from '~/vue_shared/components/icon.vue';
import panelResizer from '~/vue_shared/components/panel_resizer.vue';
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import projectTree from './ide_project_tree.vue';
import ResizablePanel from './resizable_panel.vue';
import { mapState, mapGetters } from 'vuex';
import ProjectAvatarImage from '~/vue_shared/components/project_avatar/image.vue';
import icon from '~/vue_shared/components/icon.vue';
import panelResizer from '~/vue_shared/components/panel_resizer.vue';
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import Identicon from '../../vue_shared/components/identicon.vue';
import projectTree from './ide_project_tree.vue';
import ResizablePanel from './resizable_panel.vue';
import ActivityBar from './activity_bar.vue';
export default {
components: {
projectTree,
icon,
panelResizer,
skeletonLoadingContainer,
ResizablePanel,
},
computed: {
...mapState([
'loading',
]),
...mapGetters([
'projectsWithTrees',
]),
},
};
export default {
components: {
projectTree,
icon,
panelResizer,
skeletonLoadingContainer,
ResizablePanel,
ActivityBar,
ProjectAvatarImage,
Identicon,
},
computed: {
...mapState(['loading']),
...mapGetters(['currentProjectWithTree', 'activityBarComponent']),
},
};
</script>
<template>
<resizable-panel
:collapsible="false"
:initial-width="290"
:initial-width="340"
side="left"
>
<activity-bar
v-if="!loading"
/>
<div class="multi-file-commit-panel-inner">
<template v-if="loading">
<div
@ -41,11 +46,40 @@
<skeleton-loading-container />
</div>
</template>
<project-tree
v-for="project in projectsWithTrees"
:key="project.id"
:project="project"
/>
<template v-else>
<div class="context-header">
<a
:title="currentProjectWithTree.name"
:href="currentProjectWithTree.web_url"
>
<div
v-if="currentProjectWithTree.avatar_url"
class="avatar-container s40 project-avatar"
>
<project-avatar-image
class="avatar-container project-avatar"
:link-href="currentProjectWithTree.path"
:img-src="currentProjectWithTree.avatar_url"
:img-alt="currentProjectWithTree.name"
:img-size="40"
/>
</div>
<identicon
v-else
size-class="s40"
:entity-id="currentProjectWithTree.id"
:entity-name="currentProjectWithTree.name"
/>
<div class="sidebar-context-title">
{{ currentProjectWithTree.name }}
</div>
</a>
</div>
<component
:is="activityBarComponent"
:project="currentProjectWithTree"
/>
</template>
</div>
</resizable-panel>
</template>

View file

@ -112,6 +112,10 @@ export const updateDelayViewerUpdated = ({ commit }, delay) => {
commit(types.UPDATE_DELAY_VIEWER_CHANGE, delay);
};
export const updateActivityBarView = ({ commit }, view) => {
commit(types.UPDATE_ACTIVITY_BAR_VIEW, view);
};
export * from './actions/tree';
export * from './actions/file';
export * from './actions/project';

View file

@ -1,3 +1,5 @@
import { ActivityBarViews } from './state';
export const activeFile = state => state.openFiles.find(file => file.active) || null;
export const addedFiles = state => state.changedFiles.filter(f => f.tempFile);
@ -21,6 +23,18 @@ export const projectsWithTrees = state =>
};
});
export const currentProjectWithTree = state => ({
...state.projects[state.currentProjectId],
branches: Object.keys(state.projects[state.currentProjectId].branches).map(branchId => {
const branch = state.projects[state.currentProjectId].branches[branchId];
return {
...branch,
tree: state.trees[branch.treeId],
};
}),
});
export const currentMergeRequest = state => {
if (state.projects[state.currentProjectId]) {
return state.projects[state.currentProjectId].mergeRequests[state.currentMergeRequestId];
@ -28,6 +42,8 @@ export const currentMergeRequest = state => {
return null;
};
export const currentProject = state => state.projects[state.currentProjectId];
// eslint-disable-next-line no-confusing-arrow
export const currentIcon = state =>
state.rightPanelCollapsed ? 'angle-double-left' : 'angle-double-right';
@ -35,3 +51,12 @@ export const currentIcon = state =>
export const hasChanges = state => !!state.changedFiles.length;
export const hasMergeRequest = state => !!state.currentMergeRequestId;
export const activityBarComponent = state => {
switch (state.currentActivityView) {
case ActivityBarViews.edit:
return 'project-tree';
default:
return null;
}
};

View file

@ -53,3 +53,5 @@ export const UPDATE_DELAY_VIEWER_CHANGE = 'UPDATE_DELAY_VIEWER_CHANGE';
export const ADD_PENDING_TAB = 'ADD_PENDING_TAB';
export const REMOVE_PENDING_TAB = 'REMOVE_PENDING_TAB';
export const UPDATE_ACTIVITY_BAR_VIEW = 'UPDATE_ACTIVITY_BAR_VIEW';

View file

@ -95,6 +95,11 @@ export default {
delayViewerUpdated,
});
},
[types.UPDATE_ACTIVITY_BAR_VIEW](state, currentActivityView) {
Object.assign(state, {
currentActivityView,
});
},
...projectMutations,
...mergeRequestMutation,
...fileMutations,

View file

@ -1,3 +1,8 @@
export const ActivityBarViews = {
edit: 0,
commit: 1,
};
export default () => ({
currentProjectId: '',
currentBranchId: '',
@ -17,4 +22,5 @@ export default () => ({
entries: {},
viewer: 'editor',
delayViewerUpdated: false,
currentActivityView: ActivityBarViews.edit,
});

View file

@ -177,25 +177,6 @@
}
}
// Web IDE
.ide-sidebar-link {
color: $color-200;
background-color: $color-700;
&:hover,
&:focus {
background-color: $color-500;
}
&:active {
background: $color-800;
}
}
.branch-container {
border-left-color: $color-700;
}
.branch-header-title {
color: $color-700;
}
@ -343,9 +324,5 @@ body {
.sidebar-top-level-items > li.active .badge {
color: $theme-gray-900;
}
.ide-sidebar-link {
color: $white-light;
}
}
}

View file

@ -420,27 +420,27 @@
.multi-file-commit-panel {
display: flex;
position: relative;
flex-direction: column;
width: 340px;
padding: 0;
background-color: $gray-light;
padding-right: 3px;
.context-header {
width: auto;
margin-right: 0;
}
.projects-sidebar {
display: flex;
flex-direction: column;
height: 100%;
.context-header {
width: auto;
margin-right: 0;
}
}
.multi-file-commit-panel-inner {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
.multi-file-commit-panel-inner-scroll {
@ -448,29 +448,8 @@
flex: 1;
flex-direction: column;
overflow: auto;
}
&.is-collapsed {
width: 60px;
.multi-file-commit-list {
padding-top: $gl-padding;
overflow: hidden;
}
.multi-file-context-bar-icon {
align-items: center;
svg {
float: none;
margin: 0;
}
}
}
.branch-container {
border-left: 4px solid;
margin-bottom: $gl-bar-padding;
background-color: #fff;
border-left: 1px solid #eaeaea;
}
.branch-header {
@ -491,17 +470,6 @@
.branch-header-btns {
padding: $gl-vert-padding $gl-padding;
}
.left-collapse-btn {
display: none;
background: $gray-light;
text-align: left;
border-top: 1px solid $white-dark;
svg {
vertical-align: middle;
}
}
}
.multi-file-context-bar-icon {
@ -822,12 +790,6 @@
margin-left: 25px;
}
.ide-external-links {
p {
margin: 0;
}
}
.ide-sidebar-link {
padding: $gl-padding-8 $gl-padding;
display: flex;