chore(frontend): DiscussionsSideBar component
This commit is contained in:
		
							parent
							
								
									fe397c54e3
								
							
						
					
					
						commit
						0d2b486a2c
					
				
					 4 changed files with 317 additions and 330 deletions
				
			
		
							
								
								
									
										66
									
								
								frontend/src/components/DiscussionsSideBar.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								frontend/src/components/DiscussionsSideBar.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | ||||||
|  | <script setup lang="ts"> | ||||||
|  | 
 | ||||||
|  | import type { LearningPath } from '@/data-objects/learning-paths/learning-path.ts'; | ||||||
|  | import UsingQueryResult from '@/components/UsingQueryResult.vue'; | ||||||
|  | import DiscussionSideBarElement from '@/components/DiscussionSideBarElement.vue'; | ||||||
|  | import { useI18n } from 'vue-i18n'; | ||||||
|  | import { useGetAllLearningPaths } from '@/queries/learning-paths.ts'; | ||||||
|  | import { ref } from 'vue'; | ||||||
|  | 
 | ||||||
|  | const { t, locale } = useI18n(); | ||||||
|  | 
 | ||||||
|  | const navigationDrawerShown = ref(true); | ||||||
|  | 
 | ||||||
|  | const allLearningPathsResult = useGetAllLearningPaths(locale.value); | ||||||
|  | 
 | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |     <v-navigation-drawer | ||||||
|  |         v-model="navigationDrawerShown" | ||||||
|  |         :width="350" | ||||||
|  |         app | ||||||
|  |     > | ||||||
|  |         <div class="d-flex flex-column h-100"> | ||||||
|  |             <v-list-item> | ||||||
|  |                 <template v-slot:title> | ||||||
|  |                     <div class="title">{{ t('discussions') }}</div> | ||||||
|  |                 </template> | ||||||
|  |             </v-list-item> | ||||||
|  |             <v-divider></v-divider> | ||||||
|  |             <div> | ||||||
|  |                 <using-query-result | ||||||
|  |                     :query-result="allLearningPathsResult" | ||||||
|  |                     v-slot="learningPaths: {data: LearningPath[]}"> | ||||||
|  |                     <DiscussionSideBarElement | ||||||
|  |                         v-for="learningPath in learningPaths.data" | ||||||
|  |                         :path="learningPath" | ||||||
|  |                         :activeObjectId="'' as string" | ||||||
|  |                         :key="learningPath.hruid" | ||||||
|  |                     > | ||||||
|  |                     </DiscussionSideBarElement> | ||||||
|  |                 </using-query-result> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </v-navigation-drawer> | ||||||
|  |     <div class="control-bar-above-content"> | ||||||
|  |         <v-btn | ||||||
|  |             :icon="navigationDrawerShown ? 'mdi-menu-open' : 'mdi-menu'" | ||||||
|  |             class="navigation-drawer-toggle-button" | ||||||
|  |             variant="plain" | ||||||
|  |             @click="navigationDrawerShown = !navigationDrawerShown" | ||||||
|  |         ></v-btn> | ||||||
|  |     </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <style scoped> | ||||||
|  | .title { | ||||||
|  |     color: #0e6942; | ||||||
|  |     text-transform: uppercase; | ||||||
|  |     font-weight: bolder; | ||||||
|  |     padding-top: 2%; | ||||||
|  |     font-size: 36px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | </style> | ||||||
|  | @ -57,12 +57,6 @@ const router = createRouter({ | ||||||
|                     name: "UserClasses", |                     name: "UserClasses", | ||||||
|                     component: UserClasses, |                     component: UserClasses, | ||||||
|                 }, |                 }, | ||||||
|                 // TODO Re-enable this route when the discussion page is ready
 |  | ||||||
|                 // {
 |  | ||||||
|                 //     Path: "discussion",
 |  | ||||||
|                 //     Name: "UserDiscussions",
 |  | ||||||
|                 //     Component: UserDiscussions,
 |  | ||||||
|                 // },
 |  | ||||||
|             ], |             ], | ||||||
|         }, |         }, | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,47 +1,13 @@ | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
|     import type { LearningPath } from "@/data-objects/learning-paths/learning-path.ts"; | import { useI18n } from 'vue-i18n'; | ||||||
|     import { useI18n } from "vue-i18n"; | import DiscussionsSideBar from '@/components/DiscussionsSideBar.vue'; | ||||||
|     import { useGetAllLearningPaths } from "@/queries/learning-paths.ts"; |  | ||||||
|     import UsingQueryResult from "@/components/UsingQueryResult.vue"; |  | ||||||
|     import DiscussionSideBarElement from "@/components/DiscussionSideBarElement.vue"; |  | ||||||
|     import { ref } from "vue"; |  | ||||||
| 
 | 
 | ||||||
|     const { t, locale } = useI18n(); | const { t } = useI18n(); | ||||||
| 
 |  | ||||||
|     const allLearningPathsResult = useGetAllLearningPaths(locale.value) |  | ||||||
| 
 |  | ||||||
|     const navigationDrawerShown = ref(true); |  | ||||||
| 
 | 
 | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|     <v-navigation-drawer |     <DiscussionsSideBar></DiscussionsSideBar> | ||||||
|         v-model="navigationDrawerShown" |  | ||||||
|         :width="350" |  | ||||||
|         app |  | ||||||
|     > |  | ||||||
|         <div class="d-flex flex-column h-100"> |  | ||||||
|             <v-list-item> |  | ||||||
|                 <template v-slot:title> |  | ||||||
|                     <div class="title">{{t("discussions")}}</div> |  | ||||||
|                 </template> |  | ||||||
|             </v-list-item> |  | ||||||
|             <v-divider></v-divider> |  | ||||||
|             <div> |  | ||||||
|                 <using-query-result |  | ||||||
|                     :query-result="allLearningPathsResult" |  | ||||||
|                     v-slot="learningPaths: {data: LearningPath[]}"> |  | ||||||
|                     <DiscussionSideBarElement |  | ||||||
|                         v-for="learningPath in learningPaths.data" |  | ||||||
|                         :path="learningPath" |  | ||||||
|                         :activeObjectId="'' as string" |  | ||||||
|                         :key="learningPath.hruid" |  | ||||||
|                         > |  | ||||||
|                     </DiscussionSideBarElement> |  | ||||||
|                 </using-query-result> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|     </v-navigation-drawer> |  | ||||||
|     <div> |     <div> | ||||||
|         <p class="no-discussion-tip">{{t("no-discussion-tip")}}</p> |         <p class="no-discussion-tip">{{t("no-discussion-tip")}}</p> | ||||||
|     </div> |     </div> | ||||||
|  | @ -58,13 +24,6 @@ | ||||||
|         color: #666; |         color: #666; | ||||||
|         padding: 0 20px; |         padding: 0 20px; | ||||||
|     } |     } | ||||||
|     .title { |  | ||||||
|         color: #0e6942; |  | ||||||
|         text-transform: uppercase; |  | ||||||
|         font-weight: bolder; |  | ||||||
|         padding-top: 2%; |  | ||||||
|         font-size: 36px; |  | ||||||
|     } |  | ||||||
|     .learning-path-title { |     .learning-path-title { | ||||||
|         white-space: normal; |         white-space: normal; | ||||||
|     } |     } | ||||||
|  | @ -130,19 +89,6 @@ | ||||||
|         color: #999; |         color: #999; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .send-button { |  | ||||||
|         background: none; |  | ||||||
|         border: none; |  | ||||||
|         cursor: pointer; |  | ||||||
|         font-size: 16px; |  | ||||||
|         color: #555; |  | ||||||
|         transition: color 0.2s ease; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .send-button:hover { |  | ||||||
|         color: #000; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .discussion-link { |     .discussion-link { | ||||||
|         margin-top: 8px; |         margin-top: 8px; | ||||||
|         font-size: 13px; |         font-size: 13px; | ||||||
|  |  | ||||||
|  | @ -1,27 +1,25 @@ | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
|     import { Language } from "@/data-objects/language.ts"; | import { Language } from '@/data-objects/language.ts'; | ||||||
|     import type { LearningPath } from "@/data-objects/learning-paths/learning-path.ts"; | import type { LearningPath } from '@/data-objects/learning-paths/learning-path.ts'; | ||||||
|     import { computed, type ComputedRef, ref, watch } from "vue"; | import { computed, type ComputedRef, ref, watch } from 'vue'; | ||||||
|     import type { LearningObject } from "@/data-objects/learning-objects/learning-object.ts"; | import type { LearningObject } from '@/data-objects/learning-objects/learning-object.ts'; | ||||||
|     import { useRoute } from "vue-router"; | import { useRoute } from 'vue-router'; | ||||||
|     import { useI18n } from "vue-i18n"; | import { useGetAllLearningPaths, useGetLearningPathQuery } from '@/queries/learning-paths.ts'; | ||||||
|     import { useGetAllLearningPaths, useGetLearningPathQuery } from "@/queries/learning-paths.ts"; | import { useLearningObjectListForPathQuery } from '@/queries/learning-objects.ts'; | ||||||
|     import { useLearningObjectListForPathQuery } from "@/queries/learning-objects.ts"; | import UsingQueryResult from '@/components/UsingQueryResult.vue'; | ||||||
|     import UsingQueryResult from "@/components/UsingQueryResult.vue"; | import authService from '@/services/auth/auth-service.ts'; | ||||||
|     import authService from "@/services/auth/auth-service.ts"; | import { LearningPathNode } from '@/data-objects/learning-paths/learning-path-node.ts'; | ||||||
|     import { LearningPathNode } from "@/data-objects/learning-paths/learning-path-node.ts"; | import { useCreateQuestionMutation, useQuestionsQuery } from '@/queries/questions'; | ||||||
|     import { useCreateQuestionMutation, useQuestionsQuery } from "@/queries/questions"; | import type { QuestionsResponse } from '@/controllers/questions'; | ||||||
|     import type { QuestionsResponse } from "@/controllers/questions"; | import type { LearningObjectIdentifierDTO } from '@dwengo-1/common/interfaces/learning-content'; | ||||||
|     import type { LearningObjectIdentifierDTO } from "@dwengo-1/common/interfaces/learning-content"; | import QandA from '@/components/QandA.vue'; | ||||||
|     import QandA from "@/components/QandA.vue"; | import type { QuestionData, QuestionDTO } from '@dwengo-1/common/interfaces/question'; | ||||||
|     import type { QuestionData, QuestionDTO } from "@dwengo-1/common/interfaces/question"; | import { useStudentAssignmentsQuery, useStudentGroupsQuery } from '@/queries/students'; | ||||||
|     import { useStudentAssignmentsQuery, useStudentGroupsQuery } from "@/queries/students"; | import type { AssignmentDTO } from '@dwengo-1/common/interfaces/assignment'; | ||||||
|     import type { AssignmentDTO } from "@dwengo-1/common/interfaces/assignment"; | import type { GroupDTO } from '@dwengo-1/common/interfaces/group'; | ||||||
|     import type { GroupDTO } from "@dwengo-1/common/interfaces/group"; | import DiscussionsSideBar from '@/components/DiscussionsSideBar.vue'; | ||||||
|     import DiscussionSideBarElement from "@/components/DiscussionSideBarElement.vue"; |  | ||||||
| 
 | 
 | ||||||
| const route = useRoute(); | const route = useRoute(); | ||||||
|     const { t } = useI18n(); |  | ||||||
| 
 | 
 | ||||||
| const props = defineProps<{ | const props = defineProps<{ | ||||||
|     hruid: string; |     hruid: string; | ||||||
|  | @ -48,29 +46,45 @@ | ||||||
|     return undefined; |     return undefined; | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|     const allLearningPathsResult = useGetAllLearningPaths(props.language) | const allLearningPathsResult = useGetAllLearningPaths(props.language); | ||||||
| 
 | 
 | ||||||
|     // TODO: dit moet alle leerpaden met vragen teruggeven, maar werkt niet | async function learningObjectHasQuestions(learningObject: LearningObject): Promise<boolean> { | ||||||
|     const _questionedLearningPaths = computed(() => { |  | ||||||
|         function objectHasQuestion(learningObject: LearningObject): ComputedRef<boolean> { |  | ||||||
|     const loid = { |     const loid = { | ||||||
|         hruid: learningObject.key, |         hruid: learningObject.key, | ||||||
|         version: learningObject.version, |         version: learningObject.version, | ||||||
|         language: learningObject.language, |         language: learningObject.language, | ||||||
|     } as LearningObjectIdentifierDTO; |     } as LearningObjectIdentifierDTO; | ||||||
|     const { data } = useQuestionsQuery(loid); |     const { data } = useQuestionsQuery(loid); | ||||||
|             const hasQuestions = computed(() => (data.value?.questions.length ?? 0) > 0); |     return (data.value?.questions.length ?? 0) > 0; | ||||||
|             return hasQuestions; |  | ||||||
| } | } | ||||||
|         function pathHasQuestion(learningPath: LearningPath): boolean { | 
 | ||||||
|  | async function learningPathHasQuestions(learningPath: LearningPath): Promise<boolean> { | ||||||
|     const learningPathQueryResult = useGetLearningPathQuery(learningPath.hruid, learningPath.language as Language, forGroup); |     const learningPathQueryResult = useGetLearningPathQuery(learningPath.hruid, learningPath.language as Language, forGroup); | ||||||
|     const learningObjectListQueryResult = useLearningObjectListForPathQuery(learningPathQueryResult.data); |     const learningObjectListQueryResult = useLearningObjectListForPathQuery(learningPathQueryResult.data); | ||||||
|             const learningObjects = learningObjectListQueryResult.data.value; |     const learningObjects = learningObjectListQueryResult.data.value || []; | ||||||
|             return learningObjects?.some(objectHasQuestion) || false; |     const hasQuestions = await Promise.all( | ||||||
| 
 |         learningObjects.map(async (learningObject) => learningObjectHasQuestions(learningObject)), | ||||||
|  |     ); | ||||||
|  |     return hasQuestions.some((hasQuestion) => hasQuestion); | ||||||
| } | } | ||||||
|         return allLearningPathsResult.data.value?.filter(pathHasQuestion); | 
 | ||||||
|     }) | const questionedLearningPaths = ref<LearningPath[] | null>(null); | ||||||
|  | 
 | ||||||
|  | watch( | ||||||
|  |     () => allLearningPathsResult.data.value, | ||||||
|  |     async (learningPaths) => { | ||||||
|  |         if (learningPaths) { | ||||||
|  |             const pathsWithQuestions = await Promise.all( | ||||||
|  |                 learningPaths.map(async (learningPath) => { | ||||||
|  |                     const hasQuestions = await learningPathHasQuestions(learningPath); | ||||||
|  |                     return hasQuestions ? learningPath : null; | ||||||
|  |                 }), | ||||||
|  |             ); | ||||||
|  |             questionedLearningPaths.value = pathsWithQuestions.filter((path) => path !== null); | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     { immediate: true }, | ||||||
|  | ); | ||||||
| 
 | 
 | ||||||
| const learningPathQueryResult = useGetLearningPathQuery(props.hruid, props.language, forGroup); | const learningPathQueryResult = useGetLearningPathQuery(props.hruid, props.language, forGroup); | ||||||
| 
 | 
 | ||||||
|  | @ -96,8 +110,6 @@ | ||||||
|     ), |     ), | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|     const navigationDrawerShown = ref(true); |  | ||||||
| 
 |  | ||||||
| const studentAssignmentsQueryResult = useStudentAssignmentsQuery( | const studentAssignmentsQueryResult = useStudentAssignmentsQuery( | ||||||
|     authService.authState.user?.profile.preferred_username, |     authService.authState.user?.profile.preferred_username, | ||||||
| ); | ); | ||||||
|  | @ -110,7 +122,7 @@ | ||||||
| const loID: ComputedRef<LearningObjectIdentifierDTO> = computed(() => ({ | const loID: ComputedRef<LearningObjectIdentifierDTO> = computed(() => ({ | ||||||
|     hruid: props.learningObjectHruid as string, |     hruid: props.learningObjectHruid as string, | ||||||
|     language: props.language, |     language: props.language, | ||||||
|             version: currentNode.value?.version |     version: currentNode.value?.version, | ||||||
| })); | })); | ||||||
| 
 | 
 | ||||||
| const createQuestionMutation = useCreateQuestionMutation(loID.value); | const createQuestionMutation = useCreateQuestionMutation(loID.value); | ||||||
|  | @ -120,12 +132,12 @@ | ||||||
|     () => { |     () => { | ||||||
|         //TODO: moet op een of andere manier createQuestionMutation opnieuw kunnen instellen |         //TODO: moet op een of andere manier createQuestionMutation opnieuw kunnen instellen | ||||||
|         //      Momenteel opgelost door de DiscussionsForward page workaround |         //      Momenteel opgelost door de DiscussionsForward page workaround | ||||||
|         } |     }, | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| const groupsQueryResult = useStudentGroupsQuery(authService.authState.user?.profile.preferred_username); | const groupsQueryResult = useStudentGroupsQuery(authService.authState.user?.profile.preferred_username); | ||||||
| 
 | 
 | ||||||
|     const questionInput = ref(""); | const questionInput = ref(''); | ||||||
| 
 | 
 | ||||||
| function submitQuestion(): void { | function submitQuestion(): void { | ||||||
|     const assignments = studentAssignmentsQueryResult.data.value?.assignments as AssignmentDTO[]; |     const assignments = studentAssignmentsQueryResult.data.value?.assignments as AssignmentDTO[]; | ||||||
|  | @ -139,10 +151,10 @@ | ||||||
|         content: questionInput.value, |         content: questionInput.value, | ||||||
|         inGroup: group, |         inGroup: group, | ||||||
|     }; |     }; | ||||||
|         if (questionInput.value !== "") { |     if (questionInput.value !== '') { | ||||||
|         createQuestionMutation.mutate(questionData, { |         createQuestionMutation.mutate(questionData, { | ||||||
|             onSuccess: async () => { |             onSuccess: async () => { | ||||||
|                     questionInput.value = ""; // Clear the input field after submission |                 questionInput.value = ''; // Clear the input field after submission | ||||||
|                 await getQuestionsQuery.refetch(); // Reload the questions |                 await getQuestionsQuery.refetch(); // Reload the questions | ||||||
|             }, |             }, | ||||||
|             onError: (_) => { |             onError: (_) => { | ||||||
|  | @ -157,32 +169,7 @@ | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|     <v-navigation-drawer |     <DiscussionsSideBar></DiscussionsSideBar> | ||||||
|         v-model="navigationDrawerShown" |  | ||||||
|         :width="350" |  | ||||||
|     > |  | ||||||
|         <div class="d-flex flex-column h-100"> |  | ||||||
|             <v-list-item> |  | ||||||
|                 <template v-slot:title> |  | ||||||
|                     <div class="title">{{t("discussions")}}</div> |  | ||||||
|                 </template> |  | ||||||
|             </v-list-item> |  | ||||||
|             <v-divider></v-divider> |  | ||||||
|             <div> |  | ||||||
|                 <using-query-result |  | ||||||
|                     :query-result="allLearningPathsResult" |  | ||||||
|                     v-slot="learningPaths: {data: LearningPath[]}"> |  | ||||||
|                     <DiscussionSideBarElement |  | ||||||
|                         v-for="learningPath in learningPaths.data" |  | ||||||
|                         :path="learningPath" |  | ||||||
|                         :activeObjectId="props.learningObjectHruid as string" |  | ||||||
|                         :key="learningPath.hruid" |  | ||||||
|                         > |  | ||||||
|                     </DiscussionSideBarElement> |  | ||||||
|                 </using-query-result> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|     </v-navigation-drawer> |  | ||||||
| 
 | 
 | ||||||
|     <div |     <div | ||||||
|         v-if="authService.authState.activeRole === 'student' && pathIsAssignment" |         v-if="authService.authState.activeRole === 'student' && pathIsAssignment" | ||||||
|  | @ -212,19 +199,14 @@ | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <style scoped> | <style scoped> | ||||||
|     .title { |  | ||||||
|         color: #0e6942; |  | ||||||
|         text-transform: uppercase; |  | ||||||
|         font-weight: bolder; |  | ||||||
|         padding-top: 2%; |  | ||||||
|         font-size: 36px; |  | ||||||
|     } |  | ||||||
| .learning-path-title { | .learning-path-title { | ||||||
|     white-space: normal; |     white-space: normal; | ||||||
| } | } | ||||||
|  | 
 | ||||||
| .search-field-container { | .search-field-container { | ||||||
|     min-width: 250px; |     min-width: 250px; | ||||||
| } | } | ||||||
|  | 
 | ||||||
| .control-bar-above-content { | .control-bar-above-content { | ||||||
|     margin-left: 5px; |     margin-left: 5px; | ||||||
|     margin-right: 5px; |     margin-right: 5px; | ||||||
|  | @ -232,16 +214,19 @@ | ||||||
|     display: flex; |     display: flex; | ||||||
|     justify-content: space-between; |     justify-content: space-between; | ||||||
| } | } | ||||||
|  | 
 | ||||||
| .learning-object-view-container { | .learning-object-view-container { | ||||||
|     padding-left: 20px; |     padding-left: 20px; | ||||||
|     padding-right: 20px; |     padding-right: 20px; | ||||||
|     padding-bottom: 20px; |     padding-bottom: 20px; | ||||||
| } | } | ||||||
|  | 
 | ||||||
| .navigation-buttons-container { | .navigation-buttons-container { | ||||||
|     padding: 20px; |     padding: 20px; | ||||||
|     display: flex; |     display: flex; | ||||||
|     justify-content: space-between; |     justify-content: space-between; | ||||||
| } | } | ||||||
|  | 
 | ||||||
| .assignment-indicator { | .assignment-indicator { | ||||||
|     position: absolute; |     position: absolute; | ||||||
|     bottom: 10px; |     bottom: 10px; | ||||||
|  | @ -257,12 +242,14 @@ | ||||||
|     text-transform: uppercase; |     text-transform: uppercase; | ||||||
|     z-index: 2; /* Less than modals/popups */ |     z-index: 2; /* Less than modals/popups */ | ||||||
| } | } | ||||||
|  | 
 | ||||||
| .question-box { | .question-box { | ||||||
|     width: 100%; |     width: 100%; | ||||||
|     max-width: 400px; |     max-width: 400px; | ||||||
|     margin: 20px auto; |     margin: 20px auto; | ||||||
|     font-family: sans-serif; |     font-family: sans-serif; | ||||||
| } | } | ||||||
|  | 
 | ||||||
| .input-wrapper { | .input-wrapper { | ||||||
|     display: flex; |     display: flex; | ||||||
|     align-items: center; |     align-items: center; | ||||||
|  | @ -297,12 +284,6 @@ | ||||||
|     color: #000; |     color: #000; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|     .discussion-link { |  | ||||||
|         margin-top: 8px; |  | ||||||
|         font-size: 13px; |  | ||||||
|         color: #444; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| .discussion-link a { | .discussion-link a { | ||||||
|     color: #3b82f6; /* blue */ |     color: #3b82f6; /* blue */ | ||||||
|     text-decoration: none; |     text-decoration: none; | ||||||
|  |  | ||||||
		Reference in a new issue