@saooti/octopus-sdk 41.12.0-beta2 → 41.12.0
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/.claude/scheduled_tasks.lock +1 -0
- package/CHANGELOG.md +7 -1
- package/index.ts +1 -1
- package/package.json +3 -3
- package/src/api/index.ts +1 -0
- package/src/api/radioApi.ts +18 -2
- package/src/api/rubriquesApi.ts +68 -0
- package/src/components/composable/form/useOctopusDropdown.ts +5 -2
- package/src/components/composable/usePresentationItem.ts +78 -0
- package/src/components/display/emission/EmissionInlineList.vue +1 -1
- package/src/components/display/emission/EmissionPresentationItem.vue +25 -16
- package/src/components/display/podcastmaker/PodcastmakerHeader.vue +60 -45
- package/src/components/display/podcasts/PodcastPresentationList.vue +103 -89
- package/src/components/form/ClassicButtonGroup.vue +12 -6
- package/src/components/form/OctopusMultiselect.vue +86 -9
- package/src/components/form/OctopusSelect.vue +29 -2
- package/src/components/layouts/PresentationItem.vue +149 -104
- package/src/locale/de.json +1 -0
- package/src/locale/en.json +1 -0
- package/src/locale/es.json +1 -0
- package/src/locale/fr.json +1 -0
- package/src/locale/it.json +1 -0
- package/src/locale/sl.json +1 -0
- package/src/stores/CacheStore.ts +17 -11
- package/src/stores/ParamSdkStore.ts +22 -0
- package/src/stores/class/general/organisation.ts +10 -0
- package/src/stores/class/radio/canal.ts +30 -8
- package/src/stores/class/radio/recurrence.ts +6 -5
- package/src/style/_variables.scss +2 -0
- package/src/style/bootstrap.scss +3 -2
- package/tests/components/composable/usePresentationItem.spec.ts +163 -0
- package/tests/components/display/emission/EmissionPresentationItem.spec.ts +45 -0
- package/tests/components/display/podcasts/PodcastPresentationList.spec.ts +107 -0
- package/tests/components/form/ClassicButtonGroup.spec.ts +26 -0
- package/tests/components/form/OctopusMultiselect.spec.ts +298 -0
- package/tests/components/form/OctopusSelect.spec.ts +71 -0
- package/tests/components/layouts/PresentationItem.spec.ts +36 -0
- package/tests/stores/CacheStore.spec.ts +109 -0
|
@@ -2,50 +2,71 @@
|
|
|
2
2
|
Component to display an element with its description
|
|
3
3
|
-->
|
|
4
4
|
<template>
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
>
|
|
9
|
-
<router-link
|
|
10
|
-
:to="route"
|
|
11
|
-
class="d-flex-column flex-grow-1 text-dark"
|
|
12
|
-
:class="vertical ? 'flex-column' : ''"
|
|
5
|
+
<article
|
|
6
|
+
class="classic-element-container item-presentation-container mt-3"
|
|
7
|
+
:class="vertical ? 'vertical-item' : ''"
|
|
13
8
|
>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
<img
|
|
19
|
-
v-lazy="useProxyImageUrl(imageUrl, tailleImage)"
|
|
20
|
-
:width="tailleImage"
|
|
21
|
-
:height="tailleImage"
|
|
22
|
-
aria-hidden="true"
|
|
23
|
-
:alt="name"
|
|
24
|
-
:title="name"
|
|
9
|
+
<router-link
|
|
10
|
+
:to="route"
|
|
11
|
+
class="d-flex-column flex-grow-1 text-dark"
|
|
12
|
+
:class="vertical ? 'flex-column' : ''"
|
|
25
13
|
>
|
|
14
|
+
<div
|
|
15
|
+
class="img-box"
|
|
16
|
+
:class="vertical ? 'img-box-bigger' : ''"
|
|
17
|
+
>
|
|
18
|
+
<img
|
|
19
|
+
v-lazy="useProxyImageUrl(imageUrl, tailleImage)"
|
|
20
|
+
:width="tailleImage"
|
|
21
|
+
:height="tailleImage"
|
|
22
|
+
aria-hidden="true"
|
|
23
|
+
:alt="name"
|
|
24
|
+
:title="name"
|
|
25
|
+
>
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
<div class="tags">
|
|
28
|
+
<span
|
|
29
|
+
v-for="tag in tags"
|
|
30
|
+
:key="tag"
|
|
31
|
+
>
|
|
32
|
+
{{ tag }}
|
|
33
|
+
</span>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<slot name="after-image" />
|
|
37
|
+
</div>
|
|
29
38
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
<div
|
|
40
|
+
class="classic-element-text pb-0"
|
|
41
|
+
:class="{ 'pt-1': vertical }"
|
|
42
|
+
>
|
|
43
|
+
<div class="element-name mb-2 basic-line-clamp">
|
|
44
|
+
{{ name }}
|
|
45
|
+
</div>
|
|
46
|
+
<div
|
|
47
|
+
v-if="!isPhone && description"
|
|
48
|
+
ref="descriptionItemContainer"
|
|
49
|
+
class="element-description htms-wysiwyg-content mt-0"
|
|
50
|
+
>
|
|
51
|
+
<div v-if="additionalInfo" class="mb-2">
|
|
52
|
+
<div
|
|
53
|
+
v-for="info, index in additionalInfo"
|
|
54
|
+
:key="index"
|
|
55
|
+
class="text-secondary"
|
|
56
|
+
>
|
|
57
|
+
{{ info }}
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<!-- eslint-disable vue/no-v-html -->
|
|
61
|
+
<div
|
|
62
|
+
ref="descriptionItem"
|
|
63
|
+
v-html="urlify(description || '')"
|
|
64
|
+
/>
|
|
65
|
+
<!-- eslint-enable -->
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</router-link>
|
|
69
|
+
</article>
|
|
49
70
|
</template>
|
|
50
71
|
|
|
51
72
|
<script setup lang="ts">
|
|
@@ -57,16 +78,20 @@ import { RouteLocationRaw } from "vue-router";
|
|
|
57
78
|
|
|
58
79
|
//Props
|
|
59
80
|
const props = defineProps<{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
81
|
+
/** The route to which to redirect when clicking on element */
|
|
82
|
+
route: RouteLocationRaw|string;
|
|
83
|
+
/** The URL to the image */
|
|
84
|
+
imageUrl: string;
|
|
85
|
+
/** The name of the element */
|
|
86
|
+
name: string;
|
|
87
|
+
/** Tags associated with the element (rubriques, themes, etc) */
|
|
88
|
+
tags?: Array<string>;
|
|
89
|
+
/** Additional info displayed below name */
|
|
90
|
+
additionalInfo?: Array<string>;
|
|
91
|
+
/** The description of the element */
|
|
92
|
+
description?: string;
|
|
93
|
+
/** When true display the card vertically */
|
|
94
|
+
vertical?: boolean;
|
|
70
95
|
}>();
|
|
71
96
|
|
|
72
97
|
//Data
|
|
@@ -81,78 +106,98 @@ const { useProxyImageUrl } = useImageProxy();
|
|
|
81
106
|
// Computed
|
|
82
107
|
// Calcul de la taille de l'image
|
|
83
108
|
const tailleImage = computed(() => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
109
|
+
// L'élément fait 400 de large à la verticale, mais on prend en compte les bordures
|
|
110
|
+
if (props.vertical) {
|
|
111
|
+
return '396';
|
|
112
|
+
} else if (isPhone.value) {
|
|
113
|
+
return '246';
|
|
114
|
+
} else {
|
|
115
|
+
return '250';
|
|
116
|
+
}
|
|
92
117
|
});
|
|
93
118
|
|
|
94
119
|
//Watch
|
|
95
120
|
watch(isPhone, async () => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
121
|
+
nextTick(() => {
|
|
122
|
+
if (!props.description || isPhone.value) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const itemDesc = descriptionItemRef?.value as HTMLElement;
|
|
126
|
+
const itemDescContainer = descriptionItemContainerRef?.value as HTMLElement;
|
|
127
|
+
if (
|
|
128
|
+
itemDesc &&
|
|
129
|
+
itemDescContainer &&
|
|
130
|
+
itemDesc.clientHeight > itemDescContainer.clientHeight
|
|
131
|
+
) {
|
|
132
|
+
itemDescContainer.classList.add("after-element-description");
|
|
133
|
+
}
|
|
134
|
+
});
|
|
110
135
|
}, { immediate: true });
|
|
136
|
+
|
|
111
137
|
function urlify(text:string|undefined){
|
|
112
|
-
|
|
138
|
+
return displayHelper.urlify(text);
|
|
113
139
|
}
|
|
114
140
|
</script>
|
|
115
141
|
|
|
116
142
|
<style scoped lang="scss">
|
|
117
143
|
.octopus-app {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
144
|
+
.item-presentation-container {
|
|
145
|
+
@media (width <= 960px) {
|
|
146
|
+
width: 250px !important;
|
|
147
|
+
margin-right: 0.5rem;
|
|
148
|
+
}
|
|
123
149
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
150
|
+
.element-description {
|
|
151
|
+
height: 0;
|
|
152
|
+
flex-grow: 1;
|
|
153
|
+
max-height: unset;
|
|
128
154
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
155
|
+
p:first-child {
|
|
156
|
+
// Prevent unecessary space before first paragraph
|
|
157
|
+
margin-top: 0 !important;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
133
160
|
}
|
|
134
|
-
}
|
|
135
161
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
162
|
+
.classic-element-container.vertical-item {
|
|
163
|
+
flex-grow: 0;
|
|
164
|
+
width: 400px;
|
|
165
|
+
flex-shrink: 0;
|
|
166
|
+
}
|
|
141
167
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
168
|
+
.img-box {
|
|
169
|
+
// Make it relative so that absolute elements associated with the image
|
|
170
|
+
// are positioned within the image box
|
|
171
|
+
position: relative;
|
|
146
172
|
|
|
147
|
-
|
|
148
|
-
|
|
173
|
+
@media (width <= 960px) {
|
|
174
|
+
height: calc(var(--octopus-image-size) - 4);
|
|
175
|
+
}
|
|
149
176
|
}
|
|
150
|
-
}
|
|
151
177
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
178
|
+
.img-box-bigger {
|
|
179
|
+
// L'élément fait 400 de large à la verticale, mais on prend en compte les bordures
|
|
180
|
+
width: 396px;
|
|
181
|
+
height: 396px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.tags {
|
|
185
|
+
position: absolute;
|
|
186
|
+
top: 10px;
|
|
187
|
+
left: 10px;
|
|
188
|
+
|
|
189
|
+
display: flex;
|
|
190
|
+
gap: 10px;
|
|
191
|
+
flex-wrap: wrap;
|
|
192
|
+
|
|
193
|
+
> span {
|
|
194
|
+
background-color: white;
|
|
195
|
+
padding: .25em .75em;
|
|
196
|
+
border-radius: var(--octopus-border-radius);
|
|
197
|
+
font-size: 14px;
|
|
198
|
+
font-weight: bold;
|
|
199
|
+
color: var(--octopus-primary);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
157
202
|
}
|
|
158
203
|
</style>
|
package/src/locale/de.json
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"Emission image": "Bild zur Reihe",
|
|
32
32
|
"Emission name": "Titel der Reihe",
|
|
33
33
|
"No elements found. Consider changing the search query.": "Keine Ergebnisse. Bitte ändern Sie die Suchanfrage.",
|
|
34
|
+
"Press Enter to add this value": "Drücken Sie Enter, um diesen Wert hinzuzufügen",
|
|
34
35
|
"Podcast is not visible for listeners": "Podcast ist für Hörer verborgen",
|
|
35
36
|
"Validate": "Bestätigen",
|
|
36
37
|
"Invalidate": "Invalidate",
|
package/src/locale/en.json
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"Emission image": "Series image",
|
|
32
32
|
"Emission name": "Series title",
|
|
33
33
|
"No elements found. Consider changing the search query.": "No elements found. Consider changing the search query.",
|
|
34
|
+
"Press Enter to add this value": "Press Enter to add this value",
|
|
34
35
|
"Podcast is not visible for listeners": "Podcast is not visible for listeners",
|
|
35
36
|
"Validate": "Validate",
|
|
36
37
|
"Invalidate": "Invalidate",
|
package/src/locale/es.json
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"Emission image": "Imagen del programa",
|
|
32
32
|
"Emission name": "Título del programa",
|
|
33
33
|
"No elements found. Consider changing the search query.": "No hay resultados. Prueba con otros criterios de búsqueda.",
|
|
34
|
+
"Press Enter to add this value": "Pulsa Intro para añadir este valor",
|
|
34
35
|
"Podcast is not visible for listeners": "El público no puede visualizar este pódcast",
|
|
35
36
|
"Validate": "Validar",
|
|
36
37
|
"Invalidate": "Invalidar",
|
package/src/locale/fr.json
CHANGED
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"Emission subtitle": "Sous-titre de l'émission",
|
|
38
38
|
"No elements found. Consider changing the search query.":
|
|
39
39
|
"Aucun élement ne correspond à votre recherche",
|
|
40
|
+
"Press Enter to add this value": "Appuyez sur Entrée pour ajouter cette valeur",
|
|
40
41
|
"Podcast is not visible for listeners":
|
|
41
42
|
"L'épisode n'est pas disponible pour les auditeurs",
|
|
42
43
|
"Validate": "Valider",
|
package/src/locale/it.json
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"Emission image": "Immagine della serie",
|
|
31
31
|
"Emission name": "Titolo della serie",
|
|
32
32
|
"No elements found. Consider changing the search query.": "Non è stato trovato alcun elemento. Prova a cambiare i parametri di ricerca",
|
|
33
|
+
"Press Enter to add this value": "Premi Invio per aggiungere questo valore",
|
|
33
34
|
"Podcast is not visible for listeners": "Il podcast non è visibile agli ascoltatori",
|
|
34
35
|
"Validate": "Convalidare",
|
|
35
36
|
"Invalidate": "Invalidate",
|
package/src/locale/sl.json
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"Emission image": "Slika oddaje",
|
|
32
32
|
"Emission name": "Naslov oddaje",
|
|
33
33
|
"No elements found. Consider changing the search query.": "Ni zadetkov. Spremenite poizvedbo",
|
|
34
|
+
"Press Enter to add this value": "Pritisnite Enter, da dodate to vrednost",
|
|
34
35
|
"Podcast is not visible for listeners": "Za poslušalce skrit podkast",
|
|
35
36
|
"Validate": "Potrdi",
|
|
36
37
|
"Invalidate": "Invalidate",
|
package/src/stores/CacheStore.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { useDayjs } from "
|
|
1
|
+
import { useDayjs } from "../components/composable/useDayjs";
|
|
2
2
|
import { Dayjs } from "dayjs";
|
|
3
3
|
import { defineStore } from "pinia";
|
|
4
|
-
import { reactive } from "vue";
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Type for cache storage
|
|
8
7
|
*/
|
|
9
8
|
interface CachedData<T> {
|
|
10
|
-
/** The
|
|
11
|
-
data: T
|
|
9
|
+
/** The in-flight or resolved data, shared by concurrent callers */
|
|
10
|
+
data: Promise<T>;
|
|
12
11
|
/** Expiration date of the cached data */
|
|
13
12
|
expiration: Dayjs;
|
|
14
13
|
}
|
|
@@ -16,21 +15,27 @@ interface CachedData<T> {
|
|
|
16
15
|
export const useCacheStore = defineStore('cache', () => {
|
|
17
16
|
|
|
18
17
|
const { dayjs } = useDayjs();
|
|
19
|
-
const cachedData
|
|
18
|
+
const cachedData: Record<string, CachedData<unknown>> = {};
|
|
20
19
|
|
|
21
20
|
async function getData<T>(key: string, callback: () => Promise<T>): Promise<T> {
|
|
22
21
|
let cache = cachedData[key] as CachedData<T>|undefined;
|
|
23
22
|
if (isDataEmptyOrExpired(cache)) {
|
|
24
|
-
//
|
|
25
|
-
const data =
|
|
26
|
-
const expiration = dayjs().add(
|
|
23
|
+
// Store the promise immediately so concurrent callers share this fetch
|
|
24
|
+
const data = callback();
|
|
25
|
+
const expiration = dayjs().add(30, 'minutes');
|
|
27
26
|
cache = { data, expiration };
|
|
28
27
|
cachedData[key] = cache;
|
|
28
|
+
// Don't keep a failed fetch cached: let the next call retry
|
|
29
|
+
data.catch(() => invalidate(key));
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
return cache.data;
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
function invalidate(key: string): void {
|
|
36
|
+
delete cachedData[key];
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
function isDataEmptyOrExpired(data: CachedData<unknown>|undefined): boolean {
|
|
35
40
|
if (!data) {
|
|
36
41
|
return true;
|
|
@@ -38,8 +43,9 @@ export const useCacheStore = defineStore('cache', () => {
|
|
|
38
43
|
return dayjs().isAfter(data.expiration);
|
|
39
44
|
}
|
|
40
45
|
}
|
|
41
|
-
|
|
46
|
+
|
|
42
47
|
return {
|
|
43
|
-
getData
|
|
44
|
-
|
|
48
|
+
getData,
|
|
49
|
+
invalidate
|
|
50
|
+
};
|
|
45
51
|
});
|
|
@@ -32,6 +32,9 @@ const state: ParamStore = {
|
|
|
32
32
|
},
|
|
33
33
|
smartLink: {
|
|
34
34
|
showOnlyFirstParagraphInDescription: false
|
|
35
|
+
},
|
|
36
|
+
presentationItems: {
|
|
37
|
+
tags: 'none'
|
|
35
38
|
}
|
|
36
39
|
};
|
|
37
40
|
|
|
@@ -102,6 +105,21 @@ export interface ParamStore {
|
|
|
102
105
|
sortCriteria?: PodcastSort;
|
|
103
106
|
};
|
|
104
107
|
|
|
108
|
+
/** Settings for presentation items */
|
|
109
|
+
presentationItems: {
|
|
110
|
+
/** Type of tags to display on presentation items */
|
|
111
|
+
tags: 'none'|'iab'|'rubrique';
|
|
112
|
+
/**
|
|
113
|
+
* For rubrique type, the ID of the rubriquage the rubriques must belong to
|
|
114
|
+
* to be displayed. If not set, will display all rubriques.
|
|
115
|
+
*/
|
|
116
|
+
tagsRubriquageId?: number;
|
|
117
|
+
/** Limit number of tags */
|
|
118
|
+
tagsLimit?: number;
|
|
119
|
+
/** Additional infos displayed in presentation item */
|
|
120
|
+
additionalInfo?: Array<'productor'|'date'>;
|
|
121
|
+
};
|
|
122
|
+
|
|
105
123
|
/** Smartlink configuration */
|
|
106
124
|
smartLink: {
|
|
107
125
|
/** Truncate the description to the first paragraph */
|
|
@@ -143,6 +161,10 @@ const initialize = function initialize(initObject: Partial<ParamStore>): void {
|
|
|
143
161
|
state.smartLink,
|
|
144
162
|
definedProps(initObject.smartLink)
|
|
145
163
|
);
|
|
164
|
+
state.presentationItems = Object.assign(
|
|
165
|
+
state.presentationItems,
|
|
166
|
+
definedProps(initObject.presentationItems)
|
|
167
|
+
);
|
|
146
168
|
};
|
|
147
169
|
|
|
148
170
|
export default { initialize, state };
|
|
@@ -24,12 +24,22 @@ export type OrganisationAttributes = {
|
|
|
24
24
|
PRIVATE?: string;
|
|
25
25
|
/** Live recordings enabled */
|
|
26
26
|
'live.active'?: boolean;
|
|
27
|
+
/** Videos enabled */
|
|
28
|
+
'video.active'?: boolean;
|
|
27
29
|
/**
|
|
28
30
|
* List of rubriquage **names**.
|
|
29
31
|
* The rubriques from these rubriquage are stored in stats and can be queried
|
|
30
32
|
* upon.
|
|
31
33
|
*/
|
|
32
34
|
rubriquage4MMIdentifier?: string;
|
|
35
|
+
/** Enable individualized stats */
|
|
36
|
+
nominal_analytic?: string;
|
|
37
|
+
/** Email of contact for RSS feed */
|
|
38
|
+
RSS_CONTACT?: string;
|
|
39
|
+
/** */
|
|
40
|
+
'allow-participant-rss'?: string;
|
|
41
|
+
/** Disallow RSS sharing */
|
|
42
|
+
noSharing?: string;
|
|
33
43
|
};
|
|
34
44
|
|
|
35
45
|
export interface Organisation {
|
|
@@ -1,10 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Definition for background music
|
|
3
|
+
* Only one of armbPlaylistName, mediaPlaylistId, and mixId can be defined.
|
|
4
|
+
*/
|
|
5
|
+
export interface Ambiance {
|
|
6
|
+
/** Name of known playlists to play */
|
|
7
|
+
armbPlaylistName?: string;
|
|
8
|
+
/** ID of media playlist to play */
|
|
9
|
+
mediaPlaylistId?: number;
|
|
10
|
+
/** ID of mix to play */
|
|
11
|
+
mixId?: number;
|
|
12
|
+
/** Frequency of playing autopromos (in number of songs) */
|
|
13
|
+
autopromoRatio?: number;
|
|
14
|
+
/** ID of the bac/playlist media from which to take autopromos */
|
|
15
|
+
autopromoBacId?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
1
18
|
export interface Canal {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
19
|
+
/** ID of the canal */
|
|
20
|
+
id: number;
|
|
21
|
+
/** ID of the organisation this canal belongs to */
|
|
22
|
+
organisationId: string;
|
|
23
|
+
name: string;
|
|
24
|
+
/** @deprecated, see #14467, use defaultAmbiance instead */
|
|
25
|
+
defaultPlaylist: string;
|
|
26
|
+
/** Default ambiance when nothing is playing on the canal */
|
|
27
|
+
defaultAmbiance: Ambiance;
|
|
28
|
+
url: string;
|
|
29
|
+
imageUrl: string;
|
|
30
|
+
description: string;
|
|
31
|
+
advertisingTag: null | string;
|
|
10
32
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Ambiance } from "./canal";
|
|
2
|
+
|
|
1
3
|
export interface TimeValue {
|
|
2
4
|
hours: number;
|
|
3
5
|
minutes: number;
|
|
@@ -55,11 +57,9 @@ export interface Recurrence {
|
|
|
55
57
|
crons: Array<Cron>;
|
|
56
58
|
duration: number;
|
|
57
59
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
mixId?: number;
|
|
62
|
-
}
|
|
60
|
+
|
|
61
|
+
export type AmbianceRecurrence = Recurrence & Ambiance;
|
|
62
|
+
|
|
63
63
|
export interface PlanningRecurrence extends Recurrence {
|
|
64
64
|
octopusPlaylistName: string;
|
|
65
65
|
octopusPlaylistId: number;
|
|
@@ -69,6 +69,7 @@ export interface PlanningRecurrence extends Recurrence {
|
|
|
69
69
|
advertisingTag: null | string;
|
|
70
70
|
adCount: number;
|
|
71
71
|
}
|
|
72
|
+
|
|
72
73
|
export interface Exclusion {
|
|
73
74
|
exclusionId: number;
|
|
74
75
|
validityStart: string;
|
|
@@ -49,6 +49,8 @@
|
|
|
49
49
|
--octopus-btn-play-bg: var(--octopus-primary-less-transparent);
|
|
50
50
|
--octopus-btn-play-fg: white;
|
|
51
51
|
--octopus-btn-play-radius: var(--octopus-border-radius);
|
|
52
|
+
--octopus-btn-social-bg: var(--octopus-secondary);
|
|
53
|
+
--octopus-btn-social-fg: var(--octopus-primary);
|
|
52
54
|
|
|
53
55
|
// Player
|
|
54
56
|
// Color for the transcript background
|
package/src/style/bootstrap.scss
CHANGED
|
@@ -154,7 +154,7 @@ input:not([class^="vs__"]), button:not([class^="vs__"]), select:not([class^="vs_
|
|
|
154
154
|
align-items: center;
|
|
155
155
|
justify-content: center;
|
|
156
156
|
background: var(--octopus-btn-primary-bg);
|
|
157
|
-
border: 1px solid var(--octopus-primary);
|
|
157
|
+
border: 1px solid var(--octopus-btn-primary-bg);
|
|
158
158
|
border-radius: var(--octopus-border-radius) !important;
|
|
159
159
|
color: var(--octopus-btn-primary-fg) !important;
|
|
160
160
|
font-weight: 500;
|
|
@@ -234,7 +234,8 @@ input:not([class^="vs__"]), button:not([class^="vs__"]), select:not([class^="vs_
|
|
|
234
234
|
width: 2.5rem !important;
|
|
235
235
|
height: 2.5rem !important;
|
|
236
236
|
padding: 0.5rem;
|
|
237
|
-
color : var(--octopus-
|
|
237
|
+
color : var(--octopus-btn-social-fg);
|
|
238
|
+
background-color : var(--octopus-btn-social-bg);
|
|
238
239
|
flex-shrink: 0;
|
|
239
240
|
border-radius: 50% !important;
|
|
240
241
|
|