Skip to content

Commit

Permalink
Add learning activity bar component
Browse files Browse the repository at this point in the history
  • Loading branch information
MisRob committed Jun 15, 2021
1 parent 4db150e commit 7a2e58d
Show file tree
Hide file tree
Showing 2 changed files with 462 additions and 0 deletions.
268 changes: 268 additions & 0 deletions kolibri/plugins/learn/assets/src/views/LearningActivityBar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
<template>

<UiToolbar>
<KLabeledIcon :style="{ 'margin-top': '8px' }">
<template #icon>
<LearningActivityIcon
v-if="learningActivityKind"
data-test="learningActivityIcon"
:kind="learningActivityKind"
/>
</template>
<TextTruncator
:text="resourceTitle"
:maxHeight="30"
/>
</KLabeledIcon>

<template #icon>
<KIconButton
icon="back"
data-test="backButton"
@click="onBackButtonClick"
/>
</template>

<template #actions>
<KIconButton
v-for="action in barActions"
:key="action.id"
:data-test="`bar_${action.dataTest}`"
:icon="action.icon"
:color="action.iconColor"
:tooltip="action.label"
@click="onActionClick(action.event)"
/>

<span class="menu-wrapper">
<KIconButton
v-if="menuActions.length"
ref="menuButton"
data-test="menuButton"
icon="optionsHorizontal"
tooltip="More options"
@click="toggleMenu"
/>
<CoreMenu
v-show="isMenuOpen"
ref="menu"
class="menu"
:raised="true"
:isOpen="isMenuOpen"
:containFocus="true"
@close="closeMenu"
>
<template #options>
<CoreMenuOption
v-for="action in menuActions"
:key="action.id"
:data-test="`menu_${action.dataTest}`"
:style="{ 'cursor': 'pointer' }"
@select="onActionClick(action.event)"
>
<KLabeledIcon>
<template #icon>
<KIcon
:icon="action.icon"
:color="action.iconColor"
/>
</template>
<div>{{ action.label }}</div>
</KLabeledIcon>
</CoreMenuOption>
</template>
</CoreMenu>
</span>
</template>
</UiToolbar>

</template>


<script>
import difference from 'lodash/difference';
import KResponsiveWindowMixin from 'kolibri-design-system/lib/KResponsiveWindowMixin';
import CoreMenu from 'kolibri.coreVue.components.CoreMenu';
import CoreMenuOption from 'kolibri.coreVue.components.CoreMenuOption';
import UiToolbar from 'kolibri.coreVue.components.UiToolbar';
import TextTruncator from 'kolibri.coreVue.components.TextTruncator';
import { LearningActivityKinds } from 'kolibri.coreVue.vuex.constants';
import LearningActivityIcon from './LearningActivityIcon.vue';
export default {
name: 'LearningActivityBar',
components: {
CoreMenu,
CoreMenuOption,
UiToolbar,
TextTruncator,
LearningActivityIcon,
},
mixins: [KResponsiveWindowMixin],
props: {
resourceTitle: {
type: String,
required: true,
},
/**
* Learning activity constant
*/
learningActivityKind: {
type: String,
required: true,
validator(value) {
return Object.values(LearningActivityKinds).includes(value);
},
},
/**
* Is the bar used in the context of a lesson?
* There are slight differences in rendering
* related to the context, e.g. action buttons labels.
*/
isLessonContext: {
type: Boolean,
required: false,
default: false,
},
isBookmarked: {
type: Boolean,
required: false,
default: false,
},
/**
* Does a resource have the option to be
* manually marked as complete?
* Used to determine if a button for this action
* should be displayed.
*/
allowMarkComplete: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
isMenuOpen: false,
};
},
computed: {
allActions() {
const actions = [
{
id: 'view-resource-list',
icon: 'resourceList',
label: this.isLessonContext ? 'View lesson plan' : 'View topic resources',
event: 'viewResourceList',
dataTest: this.isLessonContext ? 'viewLessonPlanButton' : 'viewTopicResourcesButton',
},
{
id: 'bookmark',
icon: this.isBookmarked ? 'bookmark' : 'bookmarkEmpty',
label: this.isBookmarked ? 'Remove from bookmarks' : 'Save to bookmarks',
event: 'toogleBookmark',
dataTest: this.isBookmarked ? 'removeBookmarkButton' : 'addBookmarkButton',
},
];
if (this.allowMarkComplete) {
actions.push({
id: 'mark-complete',
icon: 'star',
iconColor: this.$themePalette.yellow.v_700,
label: 'Mark resource as finished',
event: 'markComplete',
dataTest: 'markCompleteButton',
});
}
actions.push({
id: 'view-info',
icon: 'info',
label: 'View information',
event: 'viewInfo',
dataTest: 'viewInfoButton',
});
return actions;
},
barActions() {
const actions = [];
if (this.windowBreakpoint >= 1) {
actions.push(this.allActions.find(action => action.id === 'view-resource-list'));
}
if (this.windowBreakpoint >= 2) {
actions.push(this.allActions.find(action => action.id === 'bookmark'));
if (!this.allowMarkComplete) {
actions.push(this.allActions.find(action => action.id === 'view-info'));
}
}
return actions;
},
menuActions() {
return difference(this.allActions, this.barActions);
},
},
created() {
window.addEventListener('click', this.onWindowClick);
},
beforeDestroy() {
window.removeEventListener('click', this.onWindowClick);
},
methods: {
closeMenu({ focusMenuButton = true } = {}) {
this.isMenuOpen = false;
if (!focusMenuButton) {
return;
}
this.$nextTick(() => {
this.$refs.menuButton.$el.focus();
});
},
toggleMenu() {
this.isMenuOpen = !this.isMenuOpen;
if (!this.isMenuOpen) {
return;
}
this.$nextTick(() => {
this.$refs.menu.$el.focus();
});
},
onBackButtonClick() {
this.$emit('navigateBack');
},
onActionClick(actionEvent) {
this.$emit(actionEvent);
},
onWindowClick(event) {
if (!this.isMenuOpen) {
return;
}
// close menu on outside click
if (
!this.$refs.menu.$el.contains(event.target) &&
!this.$refs.menuButton.$el.contains(event.target)
) {
this.closeMenu({ focusMenuButton: false });
}
},
},
};
</script>


<style lang="scss" scoped>
.menu-wrapper {
position: relative;
}
.menu {
position: absolute;
top: 50%;
right: 10px; // right-align to the menu icon
min-width: 270px;
transform: translateY(16px);
}
</style>
Loading

0 comments on commit 7a2e58d

Please sign in to comment.