@saooti/octopus-sdk 41.0.14 → 41.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.ts CHANGED
@@ -38,6 +38,8 @@ export const getClassicModal = () => import("./src/components/misc/modal/Classic
38
38
  export const getClassicLazy = () => import("./src/components/misc/ClassicLazy.vue");
39
39
  export const getContractPreviewModal = () => import("./src/components/misc/modal/ContractPreviewModal.vue");
40
40
  export const getClassicModalInBody = () => import("./src/components/misc/modal/ClassicModalInBody.vue");
41
+ export const getClassicHelpButton = () => import("./src/components/misc/ClassicHelpButton.vue");
42
+ export const getClassicAlert = () => import("./src/components/misc/ClassicAlert.vue");
41
43
 
42
44
 
43
45
  //Display
@@ -151,6 +153,9 @@ export const getXIcon = () => import("./src/components/icons/XIcon.vue");
151
153
  // Routing
152
154
  import { setupRouter } from './src/router/utils';
153
155
 
156
+ // Types
157
+ import { type SelectOption } from "./src/components/form/ClassicSelect.vue";
158
+
154
159
  export {
155
160
  useResizePhone,
156
161
  useTagOf,
@@ -182,5 +187,6 @@ export {
182
187
  deepEqual,
183
188
  downloadHelper,
184
189
  displayHelper,
185
- setupRouter
190
+ setupRouter,
191
+ SelectOption,
186
192
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saooti/octopus-sdk",
3
- "version": "41.0.14",
3
+ "version": "41.0.16",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
@@ -1,8 +1,13 @@
1
+ <!--
2
+ Component displaying a list of podcasts IN A PLAYLIST
3
+ Do not confuse this with PodcastList from podcasts
4
+ -->
1
5
  <template>
2
6
  <div>
3
7
  <h3 class="mb-3 align-self-baseline">
4
8
  {{ titleList }}
5
9
  </h3>
10
+
6
11
  <ClassicSearch
7
12
  v-if="!loading && notEmptyPlaylist"
8
13
  v-model:text-init="searchPattern"
@@ -10,6 +15,7 @@
10
15
  id-search="podcast-list-search"
11
16
  :label="t('Search')"
12
17
  />
18
+
13
19
  <ListPaginate
14
20
  id="podcastPlaylistListPaginate"
15
21
  v-model:first="dfirst"
@@ -38,7 +44,12 @@
38
44
  :key="p.podcastId"
39
45
  :min-height="410"
40
46
  >
41
- <PodcastItem v-if="0 !== p.podcastId" :podcast="p" />
47
+ <PodcastItem
48
+ v-if="0 !== p.podcastId"
49
+ :podcast="p"
50
+ :in-list="true"
51
+ />
52
+
42
53
  <template #preview>
43
54
  <router-link
44
55
  :to="{
@@ -1,3 +1,8 @@
1
+ <!--
2
+ Component to display the image of a podcast.
3
+ May also display additional information, for example when an error occured
4
+ when processing the file (using PodcastPlayButton).
5
+ -->
1
6
  <template>
2
7
  <div
3
8
  v-if="podcast"
@@ -16,10 +21,9 @@
16
21
  height="270"
17
22
  aria-hidden="true"
18
23
  alt=""
19
-
20
24
  class="img-box img-box-podcast"
21
25
  :title="t('Episode name image', { name: podcast.title })"
22
- />
26
+ >
23
27
  </router-link>
24
28
  <div
25
29
  v-if="state.generalParameters.podcastmaker"
@@ -43,6 +47,7 @@
43
47
  :podcast="podcast"
44
48
  :hide-play="hidePlay"
45
49
  :fetch-conference="fetchConference"
50
+ :in-list="inList"
46
51
  />
47
52
  <button
48
53
  v-if="displayDescription && isMobile"
@@ -73,6 +78,8 @@ const props = defineProps({
73
78
  arrowDirection: { default: "up", type: String },
74
79
  isAnimatorLive: { default: false, type: Boolean },
75
80
  fetchConference: { default: undefined, type: Object as () => Conference },
81
+ /** Indicates that the podcast is displayed in a list */
82
+ inList: { default: false, type: Boolean }
76
83
  })
77
84
 
78
85
  //Emits
@@ -104,23 +111,37 @@ const isRecordedInLive = computed(() => {
104
111
  );
105
112
  });
106
113
  const statusText = computed(() => {
107
- if (!props.fetchConference) return "";
114
+ if (!props.fetchConference) {
115
+ return "";
116
+ }
117
+
108
118
  switch (props.fetchConference.status) {
109
119
  case "PLANNED":
110
120
  return t("live in few time");
121
+
111
122
  case "PENDING":
112
- if (props.isAnimatorLive) return t("Open studio");
113
- return t("live upcoming");
123
+ if (props.isAnimatorLive) {
124
+ return t("Open studio");
125
+ } else {
126
+ return t("live upcoming");
127
+ }
128
+
114
129
  case "RECORDING":
115
130
  return t("In live");
131
+
116
132
  case "DEBRIEFING":
117
- if ("READY_TO_RECORD" === props.podcast.processingStatus)
133
+ if ("READY_TO_RECORD" === props.podcast.processingStatus) {
118
134
  return t("Not recording");
119
- return t("Debriefing");
135
+ } else {
136
+ return t("Debriefing");
137
+ }
138
+
120
139
  case "ERROR":
121
140
  return t("In error");
141
+
122
142
  case "PUBLISHING":
123
143
  return t("Publishing");
144
+
124
145
  default:
125
146
  return "";
126
147
  }
@@ -10,6 +10,7 @@
10
10
  :display-description="0 !== description.length"
11
11
  :arrow-direction="arrowDirection"
12
12
  :fetch-conference="fetchConference"
13
+ :in-list="inList"
13
14
  @hide-description="hideDescription"
14
15
  @show-description="showDescription"
15
16
  />
@@ -50,7 +51,9 @@ import { Conference } from "@/stores/class/conference/conference";
50
51
  const props = defineProps({
51
52
  podcast: { default: () => ({}), type: Object as () => Podcast },
52
53
  fetchConference: { default: undefined, type: Object as () => Conference },
53
- })
54
+ /** Indicates that the podcast is displayed in a list */
55
+ inList: { default: false, type: Boolean }
56
+ });
54
57
 
55
58
  //Data
56
59
  const isMobile = ref(false);
@@ -1,3 +1,7 @@
1
+ <!--
2
+ Component displaying a list of podcast
3
+ DO NOT confuse this with PodcastList from playlist
4
+ -->
1
5
  <template>
2
6
  <ListPaginate
3
7
  id="podcastListPaginate"
@@ -28,7 +32,11 @@
28
32
  :key="p.podcastId"
29
33
  :min-height="410"
30
34
  >
31
- <PodcastItem v-if="0 !== p.podcastId" :podcast="p" />
35
+ <PodcastItem
36
+ v-if="0 !== p.podcastId"
37
+ :podcast="p"
38
+ in-list
39
+ />
32
40
  <template #preview>
33
41
  <router-link
34
42
  :to="{
@@ -1,9 +1,23 @@
1
+ <!--
2
+ Component displaying the play button on a podcast.
3
+ If the podcast is not available, an overlay is displayed with a message.
4
+ -->
1
5
  <template>
2
- <div v-if="!hidePlay || recordingLive" :class="classicPodcastPlay ? '' : 'img-blur-background'">
3
- <div v-if="!classicPodcastPlay" class="live-image-status bg-dark">
6
+ <div
7
+ v-if="!hidePlay || recordingLive"
8
+ :class="{ 'img-blur-background': displayBanner, 'allow-play': classicPodcastPlay }"
9
+ >
10
+ <div
11
+ v-if="displayBanner"
12
+ class="live-image-status bg-dark"
13
+ >
4
14
  {{ textVisible }}
5
15
  </div>
6
- <div class="multi-buttons-play" :class="justButtons ? 'play-button-relative' : ''">
16
+
17
+ <div
18
+ class="multi-buttons-play"
19
+ :class="justButtons ? 'play-button-relative' : ''"
20
+ >
7
21
  <template v-if="!isLiveToBeRecorded">
8
22
  <button
9
23
  class="d-flex"
@@ -16,8 +30,14 @@
16
30
  v-if="!playingPodcast || (playingPodcast && playerStore.playerVideo)"
17
31
  :size="'audio' === hoverType ? 50 : 40"
18
32
  />
19
- <PodcastIsPlaying v-if="playingPodcast && !playerStore.playerVideo"/>
20
- <time v-if="!isVideoPodcast" class="ms-1" :datetime="durationIso">{{ durationString }}</time>
33
+ <PodcastIsPlaying v-if="playingPodcast && !playerStore.playerVideo" />
34
+ <time
35
+ v-if="!isVideoPodcast"
36
+ class="ms-1"
37
+ :datetime="durationIso"
38
+ >
39
+ {{ durationString }}
40
+ </time>
21
41
  </button>
22
42
  <button
23
43
  v-if="isVideoPodcast"
@@ -27,15 +47,35 @@
27
47
  @mouseenter="hoverType = 'video'"
28
48
  @mouseleave="hoverType = ''"
29
49
  >
30
- <PlayVideoIcon v-if="!playerStore.playerVideo" :size="'video' === hoverType ? 50 : 40" />
31
- <PodcastIsPlaying v-if="playingPodcast && playerStore.playerVideo"/>
32
- <time class="ms-2" :datetime="durationIso">{{ durationString }}</time>
50
+ <PlayVideoIcon
51
+ v-if="!playerStore.playerVideo"
52
+ :size="'video' === hoverType ? 50 : 40"
53
+ />
54
+ <PodcastIsPlaying v-if="playingPodcast && playerStore.playerVideo" />
55
+ <time
56
+ class="ms-2"
57
+ :datetime="durationIso"
58
+ >
59
+ {{ durationString }}
60
+ </time>
33
61
  </button>
34
- <div v-if="!classicPodcastPlay" class="special-icon-play-button">
35
- <component :is="iconName" :size="16" />
62
+
63
+ <div
64
+ v-if="displayBanner"
65
+ class="special-icon-play-button"
66
+ >
67
+ <component
68
+ :is="iconName"
69
+ :size="16"
70
+ />
36
71
  </div>
37
72
  </template>
38
- <component :is="iconName" v-else :size="50" :title="textVisible" />
73
+ <component
74
+ :is="iconName"
75
+ v-else
76
+ :size="50"
77
+ :title="textVisible"
78
+ />
39
79
  </div>
40
80
  </div>
41
81
  </template>
@@ -70,6 +110,8 @@ const props = defineProps({
70
110
  hidePlay: { default: false, type: Boolean },
71
111
  fetchConference: { default: undefined, type: Object as () => Conference },
72
112
  justButtons: { default: false, type: Boolean },
113
+ /** Indicates that the podcast is displayed in a list */
114
+ inList: { default: false, type: Boolean }
73
115
  })
74
116
 
75
117
 
@@ -119,42 +161,65 @@ const isLiveValidAndVisible = computed(() => {
119
161
  props.podcast.availability.visibility
120
162
  );
121
163
  });
164
+
165
+ /** Whether the podcast can be played */
122
166
  const classicPodcastPlay = computed(() => {
123
167
  return (
124
168
  isLiveValidAndVisible.value &&
125
169
  !isLiveToBeRecorded.value &&
126
170
  ("READY_TO_RECORD" === props.podcast.processingStatus ||
127
171
  "READY" === props.podcast.processingStatus ||
128
- ("PROCESSING" === props.podcast.processingStatus &&
129
- undefined === authStore.authOrgaId))
172
+ "PROCESSING" === props.podcast.processingStatus)
130
173
  );
131
174
  });
175
+
176
+ const displayBanner = computed(() => {
177
+ return !classicPodcastPlay.value || ("PROCESSING" === props.podcast.processingStatus && !props.inList);
178
+ });
179
+
132
180
  const iconName = computed(() => {
133
- if (isLiveToBeRecorded.value) return ClockOutlineIcon;
181
+ if (isLiveToBeRecorded.value) {
182
+ return ClockOutlineIcon;
183
+ }
184
+
134
185
  if ("READY" === props.podcast.processingStatus || props.fetchConference) {
135
- if (!props.podcast.valid) return CheckIcon;
186
+ if (!props.podcast.valid) {
187
+ return CheckIcon;
188
+ }
189
+
136
190
  if (
137
191
  !props.podcast.availability.visibility &&
138
192
  props.podcast.availability.date
139
- )
193
+ ) {
140
194
  return ClockOutlineIcon;
195
+ }
196
+
141
197
  return EyeOffOutlineIcon;
142
198
  }
199
+
143
200
  if (
144
201
  "PLANNED" === props.podcast.processingStatus ||
145
202
  "PROCESSING" === props.podcast.processingStatus
146
- )
203
+ ) {
147
204
  return TimerSandEmptyIcon;
148
- if ("CANCELED" === props.podcast.processingStatus) return CancelIcon;
205
+ }
206
+
207
+ if ("CANCELED" === props.podcast.processingStatus) {
208
+ return CancelIcon;
209
+ }
149
210
  return AlertIcon;
150
211
  });
212
+
213
+ /** The text to display when the podcast is not ready */
151
214
  const textVisible = computed(() => {
152
215
  if (isLiveToBeRecorded.value){
153
216
  return t("Podcast linked to waiting live");
154
217
  }
155
218
 
156
219
  if ("READY" === props.podcast.processingStatus || props.fetchConference) {
157
- if (!props.podcast.valid) return t("Podcast to validate");
220
+ if (!props.podcast.valid) {
221
+ return t("Podcast to validate");
222
+ }
158
223
  if (
159
224
  !props.podcast.availability.visibility &&
160
225
  props.podcast.availability.date
@@ -174,6 +239,7 @@ const textVisible = computed(() => {
174
239
  }
175
240
  return t("Podcast in error");
176
241
  });
242
+
177
243
  const recordingLive = computed(() => {
178
244
  return (
179
245
  undefined !== props.fetchConference &&
@@ -188,7 +254,9 @@ const durationString = computed(() => {
188
254
  );
189
255
  });
190
256
  const durationIso = computed(() => {
191
- if (!props.podcast || props.podcast.duration <= 1) return "";
257
+ if (!props.podcast || props.podcast.duration <= 1) {
258
+ return "";
259
+ }
192
260
  return dayjs.duration({ milliseconds: props.podcast.duration }).toISOString();
193
261
  });
194
262
 
@@ -230,6 +298,10 @@ function play(isVideo: boolean): void {
230
298
  background-color:var(--octopus-background-transparent);
231
299
  // Allow pointer events to go through (allow click on image beneath blur)
232
300
  pointer-events: none;
301
+
302
+ &.allow-play {
303
+ pointer-events: all;
304
+ }
233
305
  }
234
306
 
235
307
  .live-image-status {
@@ -11,7 +11,7 @@
11
11
  :tabindex="isSwitch ? '-1' : '0'"
12
12
  @input="emit('update:textInit', !textInit)"
13
13
  @click="emitClickAction"
14
- />
14
+ >
15
15
  <button
16
16
  v-if="isSwitch"
17
17
  class="slider btn-transparent"
@@ -24,7 +24,7 @@
24
24
  <label
25
25
  class="c-hand"
26
26
  :class="[classLabel, displayLabel ? '' : 'd-none', isDisabled ? 'disabled' : '']"
27
- :for="computedIdCheckbox"
27
+ @click="clickSlider"
28
28
  >
29
29
  {{ label }}
30
30
  </label>
@@ -4,15 +4,21 @@
4
4
  :class="{ 'form-margin': displayLabel }"
5
5
  >
6
6
  <div class="d-flex align-items-center">
7
- <slot name="complementLabel"/>
7
+ <slot name="complementLabel" />
8
8
  <component
9
9
  :is="isWysiwyg? 'div': 'label'"
10
10
  :class="[classLabel, displayLabel ? '' : 'd-none']"
11
11
  :for="isWysiwyg ? '': computedInputId"
12
- >{{ label }}
13
- <AsteriskIcon v-if="displayRequired" :size="10" class="ms-1 mb-2" :title="t('Mandatory input')"/>
12
+ >
13
+ {{ label }}
14
+ <AsteriskIcon
15
+ v-if="displayRequired"
16
+ :size="10"
17
+ class="ms-1 mb-2"
18
+ :title="t('Mandatory input')"
19
+ />
14
20
  </component>
15
- <slot name="afterTitle"/>
21
+ <slot name="afterTitle" />
16
22
  <template v-if="popover">
17
23
  <button
18
24
  :id="'popover' + computedInputId"
@@ -32,9 +38,9 @@
32
38
  <!-- eslint-enable -->
33
39
  </ClassicPopover>
34
40
  </template>
35
- <slot name="afterHelp"/>
41
+ <slot name="afterHelp" />
36
42
  </div>
37
- <slot name="betweenTitleInput"/>
43
+ <slot name="betweenTitleInput" />
38
44
  <input
39
45
  v-if="!isWysiwyg && !isTextarea"
40
46
  v-show="showField"
@@ -55,7 +61,7 @@
55
61
  :disabled="isDisable"
56
62
  :required="!canBeNull"
57
63
  :autocomplete="autocompleteType"
58
- />
64
+ >
59
65
  <textarea
60
66
  v-else-if="isTextarea"
61
67
  v-show="showField"
@@ -89,10 +95,16 @@
89
95
  :is-top-position="true"
90
96
  @emoji-selected="addEmojiSelected"
91
97
  />
92
- <div v-if="isWysiwyg" class="h6">
98
+ <div
99
+ v-if="isWysiwyg"
100
+ class="h6"
101
+ >
93
102
  {{ t("Characters number calculated over HTML code") }}
94
103
  </div>
95
- <div v-else-if="'' !== indicText" class="text-indic">
104
+ <div
105
+ v-else-if="'' !== indicText"
106
+ class="text-indic"
107
+ >
96
108
  {{ indicText }}
97
109
  </div>
98
110
  <div
@@ -1,9 +1,11 @@
1
1
  <template>
2
2
  <div class="classic-select" :class="{ 'form-margin': displayLabel }">
3
- <label v-show="displayLabel" :for="idSelect" :class="classLabel">{{
4
- label
5
- }}
6
- <AsteriskIcon v-if="displayRequired" :size="10" class="ms-1 mb-2" :title="t('Mandatory input')"/></label>
3
+ <label v-show="displayLabel" :for="idSelect" :class="classLabel">
4
+ {{ label }}
5
+ <AsteriskIcon v-if="displayRequired" :size="10" class="ms-1 mb-2" :title="t('Mandatory input')"/>
6
+ <slot name="after-label" />
7
+ </label>
8
+
7
9
  <select
8
10
  :id="idSelect"
9
11
  :value="textInit"
@@ -28,37 +30,36 @@
28
30
  </select>
29
31
  </div>
30
32
  </template>
33
+
31
34
  <script setup lang="ts">
32
35
  import AsteriskIcon from "vue-material-design-icons/Asterisk.vue";
33
36
  import { computed } from "vue";
34
37
  import { useI18n } from "vue-i18n";
35
38
 
39
+ export interface SelectOption<T = number|string|undefined> {
40
+ title: string;
41
+ value: T;
42
+ fontFamily?: string;
43
+ }
44
+
36
45
  //Props
37
46
  const props = defineProps({
38
47
  idSelect: { default: "", type: String },
39
- label: { default: "", type: String },
40
- displayLabel: { default: true, type: Boolean },
41
- transparent: { default: false, type: Boolean },
42
- isDisabled: { default: false, type: Boolean },
43
- options: {
44
- default: () => [],
45
- type: Array as () => Array<{
46
- title: string;
47
- value: number | string | undefined;
48
- fontFamily?: string;
49
- }>,
50
- },
51
- topOption: { default: undefined,type: Object as () => {
52
- title: string;
53
- value: number | string | undefined;
54
- fontFamily?: string;
55
- },
56
- },
57
- textInit: { default: undefined, type: [String, Number] },
58
- classLabel: { default: "form-label", type: String },
59
- orderOptions: { default: true, type: Boolean},
60
- placeholder: { default: undefined, type: String},
61
- displayRequired: { default: false, type: Boolean },
48
+ label: { default: "", type: String },
49
+ displayLabel: { default: true, type: Boolean },
50
+ transparent: { default: false, type: Boolean },
51
+ isDisabled: { default: false, type: Boolean },
52
+ options: {
53
+ default: () => [],
54
+ type: Array as () => Array<SelectOption>,
55
+ },
56
+ topOption: { default: undefined,type: Object as () => SelectOption,
57
+ },
58
+ textInit: { default: undefined, type: [String, Number] },
59
+ classLabel: { default: "form-label", type: String },
60
+ orderOptions: { default: true, type: Boolean},
61
+ placeholder: { default: undefined, type: String},
62
+ displayRequired: { default: false, type: Boolean },
62
63
  })
63
64
 
64
65
 
@@ -100,9 +101,8 @@ function onChange(value:string){
100
101
  emit('update:textInit', value)
101
102
  }
102
103
  </script>
103
- <style lang="scss">
104
-
105
104
 
105
+ <style lang="scss">
106
106
  .octopus-app {
107
107
  select option:is(:checked, :hover){
108
108
  box-shadow: 0 0 10px 100px var(--octopus-secondary) inset;
@@ -21,7 +21,7 @@
21
21
  :src="imageUrl"
22
22
  aria-hidden="true"
23
23
  alt=""
24
- />
24
+ >
25
25
  <span>{{ title }}</span>
26
26
  <slot name="afterTitle"/>
27
27
  <ChevronDownIcon class="ms-auto" :class="{ 'arrow-transform': isOpen }" />
@@ -58,7 +58,7 @@ const emit = defineEmits(["open"]);
58
58
  const isOpen = ref(false);
59
59
 
60
60
  //Watch
61
- watch(isOpen, () => emit("open"));
61
+ watch(isOpen, () => emit("open", isOpen.value));
62
62
 
63
63
  onMounted(()=>{
64
64
  isOpen.value = props.initOpen;
@@ -0,0 +1,98 @@
1
+ <!--
2
+ Simple component to display a message to the user.
3
+ Usage:
4
+ <ClassicAlert type='info'>This is an information</ClassicAlert>
5
+ <ClassicAlert type='success'>Your changes have been saved</ClassicAlert>
6
+ <ClassicAlert type='warning'>Some data will be lost</ClassicAlert>
7
+ <ClassicAlert type='error'>An error occured while saving</ClassicAlert>
8
+ -->
9
+ <template>
10
+ <div
11
+ class="p-2 pe-4 my-2 rounded d-flex alert"
12
+ :class="cardClass"
13
+ >
14
+ <!-- The icon -->
15
+ <component
16
+ :is="iconComponent"
17
+ v-if="!noIcon"
18
+ class="icon"
19
+ :size="30"
20
+ />
21
+
22
+ <!-- Main content -->
23
+ <span class="ms-2">
24
+ <strong v-if="title">
25
+ {{ title }}
26
+ <br>
27
+ </strong>
28
+
29
+ <slot />
30
+ </span>
31
+ </div>
32
+ </template>
33
+
34
+ <script setup lang="ts">
35
+ import { computed } from 'vue';
36
+
37
+ import Alert from 'vue-material-design-icons/Alert.vue';
38
+ import CheckCircle from 'vue-material-design-icons/CheckCircle.vue';
39
+ import CloseCircle from 'vue-material-design-icons/CloseCircle.vue';
40
+ import Information from 'vue-material-design-icons/Information.vue';
41
+
42
+ const { type } = defineProps<{
43
+ /** Disables the icon when true */
44
+ noIcon?: boolean;
45
+ /** An optional title for the alert */
46
+ title?: string;
47
+ /** The type of message */
48
+ type: 'info'|'success'|'warning'|'error';
49
+ }>();
50
+
51
+ /** The class applied to the alert */
52
+ const cardClass = computed(() => {
53
+ return 'alert-' + type;
54
+ });
55
+
56
+ const iconComponent = computed(() => {
57
+ if (type === 'info') {
58
+ return Information;
59
+ } else if (type === 'success') {
60
+ return CheckCircle;
61
+ } else if (type === 'warning') {
62
+ return Alert;
63
+ } else if (type === 'error') {
64
+ return CloseCircle;
65
+ }
66
+ });
67
+ </script>
68
+
69
+ <style lang="scss" scoped>
70
+ .alert {
71
+ //color: white;
72
+ border: 1px solid;
73
+ border-left: 8px solid;
74
+
75
+ .icon {
76
+ align-items: start !important;
77
+ }
78
+
79
+ $types: (
80
+ 'success': hsl(from var(--octopus-primary) h s 45),
81
+ 'info': var(--octopus-primary),
82
+ 'warning': var(--octopus-warning),
83
+ 'error': var(--octopus-danger),
84
+ );
85
+
86
+ &.alert {
87
+ @each $type, $color in $types {
88
+ &-#{$type} {
89
+ background-color: hsl(from #{$color} h s 95) !important;
90
+ border-color: #{$color} !important;
91
+ .icon {
92
+ color: #{$color};
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ </style>
@@ -0,0 +1,50 @@
1
+ <!--
2
+ A simple component to display a help button that shows its message when
3
+ hovered.
4
+
5
+ Usage:
6
+ <ClassicHelpButton>This is my help message</ClassicHelpButton>
7
+ -->
8
+ <template>
9
+ <button
10
+ :id="computedId"
11
+ class="btn-transparent"
12
+ >
13
+ <!-- Button icon -->
14
+ <HelpCircleIcon :size="30" />
15
+
16
+ <!-- Tooltip -->
17
+ <ClassicPopover
18
+ :target="computedId"
19
+ popover-class="help-popover"
20
+ >
21
+ <div class="content">
22
+ <slot />
23
+ </div>
24
+ </ClassicPopover>
25
+ </button>
26
+ </template>
27
+
28
+ <script setup lang="ts">
29
+ import { computed, getCurrentInstance } from 'vue';
30
+
31
+ import HelpCircleIcon from "vue-material-design-icons/HelpCircle.vue";
32
+ import ClassicPopover from './ClassicPopover.vue';
33
+
34
+ /** The internal ID for the elements */
35
+ const computedId = computed(() => {
36
+ return 'popover-' + getCurrentInstance()?.uid;
37
+ });
38
+ </script>
39
+
40
+ <style lang="scss" scoped>
41
+ .content {
42
+ font: revert;
43
+ font-size: 18px !important;
44
+ text-align: start;
45
+ }
46
+
47
+ .help-popover {
48
+ background-color: var(--octopus-secondary);
49
+ }
50
+ </style>
@@ -163,14 +163,13 @@ function changeLanguage(): void {
163
163
  * @param organisation The new organisation to focus on, or undefined to remove focus
164
164
  */
165
165
  async function onOrganisationSelected( organisation: Organisation | undefined): Promise<void> {
166
- // TODO use router utils
167
166
  if (organisation?.id) {
168
167
  router.push({
169
- query: { ...route.query, ...{ productor: organisation.id, o:undefined, displayAll: "false" } },
168
+ query: { ...route.query, ...{ productor: organisation.id, o:undefined, viewall: "false" } },
170
169
  });
171
170
  }else{
172
171
  router.push({
173
- query: { ...route.query, ...{ productor: undefined, displayAll: "true" } },
172
+ query: { ...route.query, ...{ productor: undefined, viewall: "true" } },
174
173
  });
175
174
  }
176
175
  }
@@ -27,6 +27,8 @@
27
27
  :organisation-id="authOrgaId"
28
28
  />
29
29
  <CommentSection :podcast="podcast" />
30
+
31
+ <!-- Suggestions -->
30
32
  <PodcastInlineList
31
33
  :emission-id="podcast.emission.emissionId"
32
34
  :href="'/main/pub/emission/' + podcast.emission.emissionId"
@@ -39,6 +41,7 @@
39
41
  <PodcastInlineList
40
42
  class="mt-4"
41
43
  title-tag="h3"
44
+ :organisation-id="[podcast.organisation.id]"
42
45
  :podcast-id="podcastId"
43
46
  :title="t('Suggested listening')"
44
47
  />
@@ -51,6 +54,7 @@
51
54
  :href="'/main/pub/category/' + c.id"
52
55
  :title="t('More episodes of this category : ', { name: c.name })"
53
56
  :button-text="t('All podcast button', { name: c.name })"
57
+ :organisation-id="[podcast.organisation.id]"
54
58
  />
55
59
  </ClassicLazy>
56
60
  </section>
@@ -91,11 +91,11 @@ export function setupRouter(router: Router, getMyOrgaActive: (authStore: AuthSto
91
91
  newQuery.productor = filterStore.filterOrgaId;
92
92
  }
93
93
 
94
- // Enable 'displayAll' mode if already active
95
- if ((from.query.displayAll === "true" || to.query.displayAll === "true") && to.query.displayAll !== "false") {
96
- newQuery.displayAll = "true";
94
+ // Enable 'viewall' mode if already active
95
+ if ((from.query.viewall === "true" || to.query.viewall === "true") && to.query.viewall !== "false") {
96
+ newQuery.viewall = "true";
97
97
  } else {
98
- delete newQuery.displayAll;
98
+ delete newQuery.viewall;
99
99
  }
100
100
 
101
101
  // If the queries are different, update path
@@ -6,7 +6,7 @@ import { KeycloakInfo } from "@/stores/class/user/person";
6
6
  import { VideoConfig } from "@/stores/class/config/videoConfig";
7
7
  import classicApi from "../api/classicApi";
8
8
 
9
- interface AuthParam{
9
+ interface AuthParam {
10
10
  accessToken?: string;
11
11
  refreshToken?: string;
12
12
  expiration?: Date|string;
@@ -45,7 +45,7 @@ export const useAuthStore = defineStore("AuthStore", {
45
45
  comments: undefined,
46
46
  attributes: {
47
47
  RSS_CONTACT: undefined,
48
- },
48
+ }
49
49
  },
50
50
  authVideoConfig: { active: false },
51
51
  }),
@@ -32,7 +32,7 @@ export const useFilterStore = defineStore("FilterStore", () => {
32
32
  * ID of the current organisation.
33
33
  */
34
34
  const filterOrgaId = computed((): string|undefined => {
35
- if (route?.query.displayAll === "true") {
35
+ if (route?.query.viewall === "true") {
36
36
  return undefined;
37
37
  } else if (route?.query.productor) {
38
38
  return route.query.productor as string;
@@ -46,7 +46,7 @@ export const useFilterStore = defineStore("FilterStore", () => {
46
46
  /**
47
47
  * The ID of the current organisation, regardless of other options.
48
48
  * Use this if you want to know the organisation of the user even in
49
- * unfocused mode (ie displayAll = true)
49
+ * unfocused mode (ie viewall = true)
50
50
  */
51
51
  const realOrgaId = computed(() => {
52
52
  return _filterOrgaId.value ?? undefined;
@@ -22,13 +22,13 @@ export function emptyOrganisationData(): Organisation {
22
22
  return {
23
23
  imageUrl: "",
24
24
  id: "",
25
- name: "",
25
+ name: ""
26
26
  };
27
27
  }
28
28
  export function emptyOrgaData(defaultName: string): Organisation {
29
29
  return {
30
30
  imageUrl: "/img/emptypodcast.webp",
31
31
  id: "",
32
- name: defaultName,
32
+ name: defaultName
33
33
  };
34
34
  }
@@ -0,0 +1 @@
1
+ declare module 'sockjs-client/dist/sockjs';