Fix course detail title buttons

* Create BaseButton to create a consistent button across all code
* Create BaseIcon to restrict the icons used across all code
* Create BaseMenu as starting point for menu component consistent
across all code
* Fix not loaded header logo of chamilo, importing in the component
make the url resolution correctly
* Fix colors of tailwind according to figma
* Disable vuetify due to a crash with tailwind styles
pull/4713/head
Daniel Gayoso González 2 years ago
parent 90ac8fd7a1
commit af02b6b1b0
  1. 6
      .editorconfig
  2. 114
      assets/vue/components/basecomponents/BaseButton.vue
  3. 26
      assets/vue/components/basecomponents/BaseIcon.vue
  4. 45
      assets/vue/components/basecomponents/BaseMenu.vue
  5. 55
      assets/vue/components/basecomponents/ChamiloIcons.js
  6. 6
      assets/vue/components/layout/TopbarLoggedIn.vue
  7. 5
      assets/vue/components/layout/TopbarNotLoggedIn.vue
  8. 2
      assets/vue/main.js
  9. 56
      assets/vue/views/course/Home.vue
  10. 6
      tailwind.config.js
  11. 2
      webpack.config.js

@ -14,5 +14,11 @@ indent_size = 4
max_line_length = 120
ij_php_space_after_type_cast = true
[*.vue]
indent_size = 2
[*.js]
indent_size = 2
[*.vue]
indent_size = 2

@ -0,0 +1,114 @@
<template>
<Button
class="cursor-pointer"
plain
:label="label"
:class="buttonClass"
:outlined="primeOutlinedProperty"
:text="primeTextProperty"
:severity="primeSeverityProperty"
@click="$emit('click', $event)"
>
<BaseIcon class="text-inherit" :icon="icon"/>
<span
v-if="!props.onlyIcon"
class="hidden md:block text-inherit"
>
{{ label }}
</span>
</Button>
</template>
<script setup>
import Button from "primevue/button";
import {chamiloIconToClass} from "./ChamiloIcons";
import BaseIcon from "./BaseIcon.vue";
import {computed} from "vue";
const props = defineProps({
label: {
type: String,
default: "",
},
icon: {
type: String,
required: true,
validator: (value) => {
if (typeof (value) !== "string") {
return false;
}
return Object.keys(chamiloIconToClass).includes(value);
}
},
type: {
type: String,
required: true,
validator: (value) => {
if (typeof (value) !== "string") {
return false
}
return ["primary", "secondary", "black"].includes(value);
}
},
// associate this button to a popup through its identifier, this will make this button toggle the popup
popupIdentifier: {
type: String,
default: ""
},
onlyIcon: {
type: Boolean,
default: false,
}
});
defineEmits(["click"]);
const buttonClass = computed(() => {
if (props.onlyIcon) {
return "p-3";
}
let result = "py-2.5 px-4 ";
switch (props.type) {
case "primary":
result += "border-primary hover:bg-primary text-primary hover:text-white";
break;
case "secondary":
result += "bg-secondary hover:bg-secondary-gradient text-white";
break;
}
return result;
});
// https://primevue.org/button/#outlined
const primeOutlinedProperty = computed(() => {
if (props.onlyIcon) {
return false;
}
switch (props.type) {
case "primary":
return true;
case "black":
return true;
default:
return false;
}
});
// https://primevue.org/button/#text
const primeTextProperty = computed(() => {
return props.onlyIcon;
});
// https://primevue.org/button/#severity primary and secondary modified by chamilo
const primeSeverityProperty = computed(() => {
if (props.onlyIcon) {
return "primary";
}
switch (props.type) {
case "secondary":
return "danger";
default:
return "primary";
}
});
</script>

@ -0,0 +1,26 @@
<template>
<i class="text-xl/4" :class="iconClass"/>
</template>
<script setup>
import {computed} from "vue";
import {chamiloIconToClass} from "./ChamiloIcons";
const props = defineProps({
icon: {
type: String,
required: true,
validator: (value) => {
if (typeof (value) !== "string") {
return false
}
return Object.keys(chamiloIconToClass).includes(value)
}
},
});
const iconClass = computed(() => {
return chamiloIconToClass[props.icon];
});
</script>

@ -0,0 +1,45 @@
<template>
<Menu
:id="id"
ref="menu"
:model="innerModel"
:popup="true"
class="app-topbar__user-submenu"
/>
<!-- this class should use tailwind in the future -->
</template>
<script setup>
import Menu from "primevue/menu";
import {ref, computed} from "vue";
const props = defineProps({
id: {
type: String,
required: true,
},
model: {
type: Array,
required: true,
},
})
const innerModel = computed(() => {
return props.model.map(e => {
return {
...e,
'class': 'text-primary',
};
});
})
const menu = ref(null);
const toggle = (event) => {
menu.value.toggle(event);
};
defineExpose({
toggle,
});
</script>

@ -0,0 +1,55 @@
/**
* Use it like chamiloIconToClass['eye'] to get the correct class for an icon
*
* Transform name of icons according to https://github.com/chamilo/chamilo-lms/wiki/Graphical-design-guide#default-icons-terminology
* to the classes needed for represent every icon
*/
export const chamiloIconToClass = {
"pencil": "mdi mdi-pencil",
"delete": "",
"hammer-wrench": "",
"download": "",
"download-box": "",
"upload": "",
"arrow-left-bold-box": "",
"account-multiple-plus": "",
"cursor-move": "",
"chevron-left": "",
"chevron-right": "",
"arrow-up-bold": "",
"arrow-down-bold": "",
"arrow-right-bold": "",
"magnify-plus-outline": "",
"archive-arrow-up": "",
"folder-multiple-plus": "",
"folder-plus": "",
"alert": "",
"checkbox-marked": "",
"pencil-off": "",
"eye": "mdi mdi-eye",
"eye-off": "",
"checkbox-multiple-blank": "",
"checkbox-multiple-blank-outline": "",
"sync": "",
"sync-circle": "",
"fullscreen": "",
"fullscreen-exit": "",
"overscan": "",
"play-box-outline": "",
"fit-to-screen": "",
"bug-check": "",
"bug-outline": "",
"package": "",
"text-box-plus": "",
"rocket-launch": "",
"file-pdf-box": "",
"content-save": "",
"send": "",
"file-plus": "",
"cloud-upload": "",
"dots-vertical": "",
"information": "",
"account-key": "",
"cog": "mdi mdi-cog",
"plus": "mdi mdi-plus",
};

@ -3,7 +3,7 @@
<template #start>
<img
alt="Chamilo LMS"
src="/build/css/themes/chamilo/images/header-logo.svg"
:src="headerLogo"
/>
</template>
@ -52,6 +52,8 @@ import Avatar from "primevue/avatar";
import Menu from "primevue/menu";
import { usePlatformConfig } from "../../store/platformConfig";
import headerLogoPath from "../../../../assets/css/themes/chamilo/images/header-logo.svg";
// eslint-disable-next-line no-undef
const props = defineProps({
currentUser: {
@ -113,4 +115,6 @@ const userSubmenuItems = [
function toogleUserMenu(event) {
elUserSubmenu.value.toggle(event);
}
const headerLogo = headerLogoPath;
</script>

@ -6,7 +6,7 @@
<template #start>
<img
alt="Chamilo LMS"
src="/build/css/themes/chamilo/images/header-logo.svg"
:src="headerLogo"
>
</template>
</Menubar>
@ -16,6 +16,7 @@
<script setup>
import {ref} from 'vue';
import Menubar from 'primevue/menubar';
import headerLogoPath from "../../../../assets/css/themes/chamilo/images/header-logo.svg";
function setLanguage(event) {
const {label} = event.item;
@ -51,4 +52,6 @@ const menuItems = ref([
],
}
]);
const headerLogo = headerLogoPath;
</script>

@ -285,7 +285,7 @@ app
.use(Quasar, quasarUserOptions)
.use(VueFlatPickr)
//.use(VuelidatePlugin)
.use(vuetify)
// .use(vuetify)
.use(router)
.use(store)
.use(pinia)

@ -82,29 +82,34 @@
</small>
</h2>
<Button
<BaseButton
v-if="course && isCurrentTeacher"
type="black"
:label="t('See as student')"
class="p-button-outlined p-button-plain"
icon="pi pi-eye"
type="button"
icon="eye"
/>
<Button
<BaseButton
v-if="showUpdateIntroductionButton"
type="black"
:label="t('Edit introduction')"
icon="pencil"
@click="updateIntro(intro)"
/>
<BaseButton
v-if="course && isCurrentTeacher"
aria-controls="course-tmenu"
aria-haspopup="true"
class="p-button-text p-button-plain"
icon="mdi mdi-cog"
type="button"
type="black"
popup-identifier="course-tmenu"
icon="cog"
only-icon
@click="toggleCourseTMenu"
/>
<TieredMenu
<BaseMenu
id="course-tmenu"
ref="courseTMenu"
:model="courseItems"
:popup="true"
/>
</div>
@ -117,20 +122,14 @@
>
<div v-html="intro.introText" />
<Button
<BaseButton
v-if="createInSession && introTool"
:label="t('Course introduction')"
class="p-button-outlined ml-auto"
icon="mdi mdi-plus"
class="ml-auto"
type="primary"
icon="plus"
@click="addIntro(course, introTool)"
/>
<Button
v-else
:label="t('Update')"
class="p-button-outlined ml-auto"
icon="mdi mdi-pencil"
@click="updateIntro(intro)"
/>
</div>
<EmptyState
v-else-if="introTool"
@ -138,10 +137,11 @@
:summary="t('You don\'t have any course content yet.')"
icon="mdi mdi-book-open-page-variant"
>
<Button
<BaseButton
:label="t('Course introduction')"
class="mt-4 p-button-outlined"
icon="mdi mdi-plus"
class="mt-4"
type="primary"
icon="plus"
@click="addIntro(course, introTool)"
/>
</EmptyState>
@ -243,12 +243,13 @@ import axios from "axios";
import { ENTRYPOINT } from "../../config/entrypoint";
import Button from "primevue/button";
import ToggleButton from "primevue/togglebutton";
import TieredMenu from "primevue/tieredmenu";
import CourseToolList from "../../components/course/CourseToolList.vue";
import ShortCutList from "../../components/course/ShortCutList.vue";
import translateHtml from "../../../js/translatehtml.js";
import EmptyState from "../../components/EmptyState";
import Skeleton from "primevue/skeleton";
import BaseButton from "../../components/basecomponents/BaseButton.vue";
import BaseMenu from "../../components/basecomponents/BaseMenu.vue";
const route = useRoute();
const store = useStore();
@ -268,6 +269,9 @@ let sessionId = route.query.sid ?? 0;
const isCourseLoading = ref(true);
const showUpdateIntroductionButton = computed(() => {
return course.value && isCurrentTeacher.value && intro.value && !(createInSession.value && introTool.value)
})
const isCurrentTeacher = computed(() => store.getters["security/isCurrentTeacher"]);
const isSorting = ref(false);

@ -1,6 +1,7 @@
const colors = require("tailwindcss/colors");
module.exports = {
important: true,
content: [
"./assets/**/*.{js,vue}",
"./public/main/**/*.{php,twig}",
@ -12,7 +13,10 @@ module.exports = {
DEFAULT: "#2e75a3",
gradient: "#9CC2DA",
},
secondary: "#fd6600",
secondary: {
DEFAULT: "#F37E2F",
gradient: "#e06410",
},
gray: {
5: "#fcfcfc",
10: "#fafafa",

@ -8,7 +8,7 @@ const PurgeCssPlugin = require('purgecss-webpack-plugin');
const glob = require('glob-all');
const path = require('path');
const { VuetifyLoaderPlugin } = require('vuetify-loader')
// const { VuetifyLoaderPlugin } = require('vuetify-loader')
const CopyPlugin = require('copy-webpack-plugin');
Encore

Loading…
Cancel
Save