DependencyTree.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <template>
  2. <div class="flex justify-end items-center">
  3. <button
  4. v-for="lang in availableLanguages"
  5. :key="lang"
  6. class="language-button"
  7. :disabled="lang == activeLang"
  8. :title="`Modulabhängigkeits-Sprache ändern auf ${lang}`"
  9. @click="activeLang = lang"
  10. >
  11. {{ lang }}
  12. </button>
  13. <div
  14. v-if="hasData && availableLanguages.length > 0"
  15. :title="`Die ${SCHOOL_NAME} hat teils Modulbeschreibungen in Deutsch & Englisch. Je nach Sprache des Unterrichts, können sich die Abhängigkeiten ändern. Standardmässig wir die Sprache des Unterrichts ausgewählt, sonst die erst verfügbare Sprache.`"
  16. class="mx-2 w-5 h-5 text-xs aspect-square rounded-full bg-gray-200 dark:bg-gray-400 inline-flex items-center justify-center cursor-help"
  17. >
  18. <font-awesome-icon icon="fa-solid fa-info" />
  19. </div>
  20. </div>
  21. <div class="mt-5">
  22. <div
  23. v-if="module && hasEnablers"
  24. class="flex justify-center flex-wrap gap-3"
  25. >
  26. <button
  27. v-for="dep in module.enablingModules[activeLang]"
  28. :key="dep"
  29. class="module-box"
  30. title="Modulinformationen anzeigen"
  31. :class="[rowStyling(moduleStore.fromModuleShort(dep), defaultActionBG)]"
  32. @click="stateStore.inspectingModule = moduleStore.fromModuleShort(dep)"
  33. >
  34. {{ dep }}
  35. </button>
  36. </div>
  37. <div
  38. v-else
  39. class="flex justify-center flex-wrap gap-3"
  40. >
  41. <span class="text-gray-500">Keine Nachfolgemodule</span>
  42. </div>
  43. <div class="flex justify-center mt-3">
  44. <font-awesome-icon icon="fa-solid fa-arrow-up" />
  45. </div>
  46. <div class="flex justify-center mt-3">
  47. <button
  48. class="module-box font-bold"
  49. :class="[rowStyling(module, defaultActionBG)]"
  50. title="Modulinformationen anzeigen"
  51. @click="stateStore.inspectingModule = module"
  52. >
  53. {{ module?.short ?? moduleName }}
  54. </button>
  55. </div>
  56. <div class="flex justify-center mt-3">
  57. <font-awesome-icon icon="fa-solid fa-arrow-up" />
  58. </div>
  59. <div
  60. v-if="module && hasDeps"
  61. class="flex justify-center flex-wrap gap-3 mt-3"
  62. >
  63. <button
  64. v-for="dep in module.dependencies[activeLang]"
  65. :key="dep"
  66. class="module-box"
  67. title="Modulinformationen anzeigen"
  68. :class="[rowStyling(moduleStore.fromModuleShort(dep), defaultActionBG)]"
  69. @click="stateStore.inspectingModule = moduleStore.fromModuleShort(dep)"
  70. >
  71. {{ dep }}
  72. </button>
  73. </div>
  74. <div
  75. v-else
  76. class="flex justify-center flex-wrap gap-3 mt-3"
  77. >
  78. <span class="text-gray-500">Keine Abhängigkeiten</span>
  79. </div>
  80. </div>
  81. </template>
  82. <script lang="ts">
  83. import { PropType } from "vue";
  84. import { useModulesStore } from "../../stores/modules";
  85. import { useStateStore } from "../../stores/state";
  86. import { Module, ModuleLanguages } from "../../types";
  87. import { rowStyling, SCHOOL_NAME } from "../../helpers";
  88. function availableLanguages(module: Module): string[] {
  89. const deps = module.dependencies;
  90. const langs = Object.keys(deps).filter((o) => deps[o].length > 0);
  91. const eDeps = module.enablingModules;
  92. langs.push(...Object.keys(eDeps).filter((o) => eDeps[o].length > 0));
  93. return [...new Set(langs)];
  94. }
  95. export default {
  96. name: "DependencyTree",
  97. props: {
  98. module: {
  99. required: true,
  100. type: Object as PropType<Module | null>,
  101. },
  102. moduleName: {
  103. required: true,
  104. type: String,
  105. },
  106. classLanguage: {
  107. required: false,
  108. type: String,
  109. default: ModuleLanguages.DE,
  110. },
  111. },
  112. setup() {
  113. const stateStore = useStateStore();
  114. const moduleStore = useModulesStore();
  115. return {
  116. stateStore,
  117. moduleStore,
  118. rowStyling,
  119. defaultActionBG: "bg-gray-200 dark:bg-gray-600",
  120. SCHOOL_NAME,
  121. };
  122. },
  123. data() {
  124. let lang = this.classLanguage ?? "";
  125. if (this.module !== null) {
  126. const available = availableLanguages(this.module);
  127. if (available.length > 0 && !available.includes(lang))
  128. lang = available[0];
  129. }
  130. return {
  131. activeLang: lang,
  132. };
  133. },
  134. computed: {
  135. availableLanguages(): string[] {
  136. if (this.module === null) return [];
  137. return availableLanguages(this.module);
  138. },
  139. hasDeps(): boolean {
  140. return (
  141. this.module !== null &&
  142. this.module.dependencies[this.activeLang]?.length > 0
  143. );
  144. },
  145. hasEnablers(): boolean {
  146. return (
  147. this.module !== null &&
  148. (this.module.enablingModules[this.activeLang]?.length ?? 0) > 0
  149. );
  150. },
  151. hasData(): boolean {
  152. return this.hasDeps || this.hasEnablers;
  153. },
  154. },
  155. };
  156. </script>
  157. <style scoped>
  158. .module-box {
  159. @apply w-28
  160. py-2
  161. rounded
  162. text-center
  163. hover:bg-gray-300
  164. active:bg-gray-400
  165. dark:hover:bg-gray-700
  166. dark:active:bg-gray-900
  167. cursor-pointer
  168. transition-all
  169. duration-200;
  170. }
  171. .language-button {
  172. @apply text-center
  173. bg-gray-200
  174. hover:bg-gray-300
  175. active:bg-gray-400
  176. dark:bg-gray-600
  177. dark:hover:bg-gray-700
  178. dark:active:bg-gray-900
  179. rounded
  180. cursor-pointer
  181. px-2
  182. py-0.5
  183. ml-2
  184. transition-all
  185. duration-200
  186. disabled:dark:bg-blue-600
  187. disabled:dark:text-gray-300
  188. disabled:text-gray-400
  189. disabled:bg-gray-100
  190. disabled:pointer-events-none;
  191. }
  192. </style>