@abraca/nuxt 2.0.4 → 2.0.6
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/dist/module.json +1 -1
- package/dist/runtime/components/aware/AAvatar.d.vue.ts +4 -0
- package/dist/runtime/components/aware/AAvatar.vue +17 -4
- package/dist/runtime/components/aware/AAvatar.vue.d.ts +4 -0
- package/dist/runtime/components/aware/AInputMenu.vue +8 -2
- package/dist/runtime/components/aware/AMedia.d.vue.ts +1 -1
- package/dist/runtime/components/aware/AMedia.vue.d.ts +1 -1
- package/dist/runtime/components/aware/ASelectMenu.vue +8 -2
- package/dist/runtime/components/docs/ADocsSearch.d.vue.ts +1 -1
- package/dist/runtime/components/docs/ADocsSearch.vue.d.ts +1 -1
- package/dist/runtime/components/renderers/AMapRenderer.vue +14 -3
- package/dist/runtime/components/renderers/media/MediaPlaylist.d.vue.ts +0 -5
- package/dist/runtime/components/renderers/media/MediaPlaylist.vue +10 -6
- package/dist/runtime/components/renderers/media/MediaPlaylist.vue.d.ts +0 -5
- package/dist/runtime/components/renderers/media/MediaSyncBar.d.vue.ts +0 -4
- package/dist/runtime/components/renderers/media/MediaSyncBar.vue +10 -6
- package/dist/runtime/components/renderers/media/MediaSyncBar.vue.d.ts +0 -4
- package/dist/runtime/components/shell/AUserMenu.d.vue.ts +2 -2
- package/dist/runtime/components/shell/AUserMenu.vue.d.ts +2 -2
- package/dist/runtime/utils/avatarStyle.d.ts +4 -2
- package/dist/runtime/utils/avatarStyle.js +6 -2
- package/package.json +3 -3
package/dist/module.json
CHANGED
|
@@ -15,12 +15,16 @@ type __VLS_Props = {
|
|
|
15
15
|
* the consumer can opt into the look without affecting other call
|
|
16
16
|
* sites (e.g. show on the local user's own avatar but not on peers). */
|
|
17
17
|
useStatusAsAvatar?: boolean;
|
|
18
|
+
/** Free-form icon override. Takes precedence over `useStatusAsAvatar`.
|
|
19
|
+
* Accepts a Lucide icon name (`smile`) or a full Iconify name (`i-lucide-smile`). */
|
|
20
|
+
icon?: string;
|
|
18
21
|
};
|
|
19
22
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
20
23
|
follow: (user: AwarenessUser) => any;
|
|
21
24
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
22
25
|
onFollow?: ((user: AwarenessUser) => any) | undefined;
|
|
23
26
|
}>, {
|
|
27
|
+
icon: string;
|
|
24
28
|
size: "2xs" | "xs" | "sm" | "md" | "lg";
|
|
25
29
|
showStatus: boolean;
|
|
26
30
|
showTooltip: boolean;
|
|
@@ -10,7 +10,8 @@ const props = defineProps({
|
|
|
10
10
|
showTooltip: { type: Boolean, required: false, default: true },
|
|
11
11
|
showPopover: { type: Boolean, required: false, default: false },
|
|
12
12
|
currentDocId: { type: String, required: false },
|
|
13
|
-
useStatusAsAvatar: { type: Boolean, required: false, default: false }
|
|
13
|
+
useStatusAsAvatar: { type: Boolean, required: false, default: false },
|
|
14
|
+
icon: { type: String, required: false, default: "" }
|
|
14
15
|
});
|
|
15
16
|
const emit = defineEmits(["follow"]);
|
|
16
17
|
const appConfig = useAppConfig();
|
|
@@ -22,7 +23,14 @@ const statusIcon = computed(
|
|
|
22
23
|
() => statusIconRaw.value ? statusIconRaw.value.startsWith("i-") ? statusIconRaw.value : `i-lucide-${statusIconRaw.value}` : ""
|
|
23
24
|
);
|
|
24
25
|
const statusText = computed(() => props.user.user?.statusText ?? "");
|
|
25
|
-
const
|
|
26
|
+
const explicitIcon = computed(
|
|
27
|
+
() => props.icon ? props.icon.startsWith("i-") ? props.icon : `i-lucide-${props.icon}` : ""
|
|
28
|
+
);
|
|
29
|
+
const avatarIcon = computed(() => {
|
|
30
|
+
if (explicitIcon.value) return explicitIcon.value;
|
|
31
|
+
if (props.useStatusAsAvatar && statusIcon.value) return statusIcon.value;
|
|
32
|
+
return void 0;
|
|
33
|
+
});
|
|
26
34
|
const avatarStyle = computed(
|
|
27
35
|
() => color.value ? avatarBorderStyle(color.value, neutral.value) : ""
|
|
28
36
|
);
|
|
@@ -77,6 +85,7 @@ const popoverOpen = ref(false);
|
|
|
77
85
|
:alt="name"
|
|
78
86
|
:size="size"
|
|
79
87
|
:style="avatarStyle"
|
|
88
|
+
:icon="avatarIcon"
|
|
80
89
|
/>
|
|
81
90
|
</UChip>
|
|
82
91
|
<UAvatar
|
|
@@ -84,6 +93,7 @@ const popoverOpen = ref(false);
|
|
|
84
93
|
:alt="name"
|
|
85
94
|
:size="size"
|
|
86
95
|
:style="avatarStyle"
|
|
96
|
+
:icon="avatarIcon"
|
|
87
97
|
/>
|
|
88
98
|
</UTooltip>
|
|
89
99
|
<UAvatar
|
|
@@ -91,6 +101,7 @@ const popoverOpen = ref(false);
|
|
|
91
101
|
:alt="name"
|
|
92
102
|
:size="size"
|
|
93
103
|
:style="avatarStyle"
|
|
104
|
+
:icon="avatarIcon"
|
|
94
105
|
/>
|
|
95
106
|
|
|
96
107
|
<template #content>
|
|
@@ -100,6 +111,7 @@ const popoverOpen = ref(false);
|
|
|
100
111
|
:alt="name"
|
|
101
112
|
size="md"
|
|
102
113
|
:style="avatarStyle"
|
|
114
|
+
:icon="avatarIcon"
|
|
103
115
|
/>
|
|
104
116
|
<div class="flex-1 min-w-0">
|
|
105
117
|
<p class="text-sm font-semibold text-default truncate">
|
|
@@ -151,7 +163,7 @@ const popoverOpen = ref(false);
|
|
|
151
163
|
:alt="name"
|
|
152
164
|
:size="size"
|
|
153
165
|
:style="avatarStyle"
|
|
154
|
-
:icon="
|
|
166
|
+
:icon="avatarIcon"
|
|
155
167
|
/>
|
|
156
168
|
</UChip>
|
|
157
169
|
<UAvatar
|
|
@@ -174,7 +186,7 @@ const popoverOpen = ref(false);
|
|
|
174
186
|
:alt="name"
|
|
175
187
|
:size="size"
|
|
176
188
|
:style="avatarStyle"
|
|
177
|
-
:icon="
|
|
189
|
+
:icon="avatarIcon"
|
|
178
190
|
/>
|
|
179
191
|
</UChip>
|
|
180
192
|
<UAvatar
|
|
@@ -182,6 +194,7 @@ const popoverOpen = ref(false);
|
|
|
182
194
|
:alt="name"
|
|
183
195
|
:size="size"
|
|
184
196
|
:style="avatarStyle"
|
|
197
|
+
:icon="avatarIcon"
|
|
185
198
|
/>
|
|
186
199
|
</template>
|
|
187
200
|
</template>
|
|
@@ -15,12 +15,16 @@ type __VLS_Props = {
|
|
|
15
15
|
* the consumer can opt into the look without affecting other call
|
|
16
16
|
* sites (e.g. show on the local user's own avatar but not on peers). */
|
|
17
17
|
useStatusAsAvatar?: boolean;
|
|
18
|
+
/** Free-form icon override. Takes precedence over `useStatusAsAvatar`.
|
|
19
|
+
* Accepts a Lucide icon name (`smile`) or a full Iconify name (`i-lucide-smile`). */
|
|
20
|
+
icon?: string;
|
|
18
21
|
};
|
|
19
22
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
20
23
|
follow: (user: AwarenessUser) => any;
|
|
21
24
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
22
25
|
onFollow?: ((user: AwarenessUser) => any) | undefined;
|
|
23
26
|
}>, {
|
|
27
|
+
icon: string;
|
|
24
28
|
size: "2xs" | "xs" | "sm" | "md" | "lg";
|
|
25
29
|
showStatus: boolean;
|
|
26
30
|
showTooltip: boolean;
|
|
@@ -30,6 +30,12 @@ const enableLive = computed(() => props.live || props.total);
|
|
|
30
30
|
const attrs = useAttrs();
|
|
31
31
|
const { hoverers, focusers, pressers, isPressed, handlers } = useAAField(() => props.fieldKey);
|
|
32
32
|
const synced = useAAFieldValue(() => props.fieldKey);
|
|
33
|
+
const syncedModel = computed({
|
|
34
|
+
get: () => synced.value,
|
|
35
|
+
set: (v) => {
|
|
36
|
+
synced.value = v;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
33
39
|
const liveOpen = useAAUIState(() => `${props.fieldKey}:open`, { defaultValue: false });
|
|
34
40
|
const liveQuery = useAAUIState(() => `${props.fieldKey}:query`, { defaultValue: "" });
|
|
35
41
|
const hasExternalModel = computed(() => "modelValue" in attrs || "onUpdate:modelValue" in attrs);
|
|
@@ -81,7 +87,7 @@ const eventHandlers = computed(() => enableAwareness.value ? handlers : {});
|
|
|
81
87
|
>
|
|
82
88
|
<UInputMenu
|
|
83
89
|
v-if="enableSync && !hasExternalModel && enableLive && !hasExternalOpen"
|
|
84
|
-
v-model="
|
|
90
|
+
v-model="syncedModel"
|
|
85
91
|
v-model:open="localOpen"
|
|
86
92
|
v-model:search-term="localQuery"
|
|
87
93
|
v-bind="attrs"
|
|
@@ -94,7 +100,7 @@ const eventHandlers = computed(() => enableAwareness.value ? handlers : {});
|
|
|
94
100
|
</UInputMenu>
|
|
95
101
|
<UInputMenu
|
|
96
102
|
v-else-if="enableSync && !hasExternalModel"
|
|
97
|
-
v-model="
|
|
103
|
+
v-model="syncedModel"
|
|
98
104
|
v-bind="attrs"
|
|
99
105
|
>
|
|
100
106
|
<template #item="{ item }">
|
|
@@ -12,8 +12,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
12
12
|
awareness: boolean;
|
|
13
13
|
tag: "video" | "audio";
|
|
14
14
|
live: boolean;
|
|
15
|
-
controls: boolean;
|
|
16
15
|
total: boolean;
|
|
16
|
+
controls: boolean;
|
|
17
17
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
18
|
declare const _default: typeof __VLS_export;
|
|
19
19
|
export default _default;
|
|
@@ -12,8 +12,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
12
12
|
awareness: boolean;
|
|
13
13
|
tag: "video" | "audio";
|
|
14
14
|
live: boolean;
|
|
15
|
-
controls: boolean;
|
|
16
15
|
total: boolean;
|
|
16
|
+
controls: boolean;
|
|
17
17
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
18
|
declare const _default: typeof __VLS_export;
|
|
19
19
|
export default _default;
|
|
@@ -30,6 +30,12 @@ const enableLive = computed(() => props.live || props.total);
|
|
|
30
30
|
const attrs = useAttrs();
|
|
31
31
|
const { hoverers, focusers, pressers, isPressed, handlers } = useAAField(() => props.fieldKey);
|
|
32
32
|
const synced = useAAFieldValue(() => props.fieldKey);
|
|
33
|
+
const syncedModel = computed({
|
|
34
|
+
get: () => synced.value,
|
|
35
|
+
set: (v) => {
|
|
36
|
+
synced.value = v;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
33
39
|
const liveOpen = useAAUIState(() => `${props.fieldKey}:open`, { defaultValue: false });
|
|
34
40
|
const liveQuery = useAAUIState(() => `${props.fieldKey}:query`, { defaultValue: "" });
|
|
35
41
|
const hasExternalModel = computed(() => "modelValue" in attrs || "onUpdate:modelValue" in attrs);
|
|
@@ -82,7 +88,7 @@ const eventHandlers = computed(() => enableAwareness.value ? handlers : {});
|
|
|
82
88
|
>
|
|
83
89
|
<USelectMenu
|
|
84
90
|
v-if="enableSync && !hasExternalModel && enableLive && !hasExternalOpen"
|
|
85
|
-
v-model="
|
|
91
|
+
v-model="syncedModel"
|
|
86
92
|
v-model:open="localOpen"
|
|
87
93
|
v-model:search-term="localQuery"
|
|
88
94
|
v-bind="attrs"
|
|
@@ -95,7 +101,7 @@ const eventHandlers = computed(() => enableAwareness.value ? handlers : {});
|
|
|
95
101
|
</USelectMenu>
|
|
96
102
|
<USelectMenu
|
|
97
103
|
v-else-if="enableSync && !hasExternalModel"
|
|
98
|
-
v-model="
|
|
104
|
+
v-model="syncedModel"
|
|
99
105
|
v-bind="attrs"
|
|
100
106
|
>
|
|
101
107
|
<template #item="{ item }">
|
|
@@ -238,8 +238,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
|
|
|
238
238
|
transition: boolean;
|
|
239
239
|
autofocus: boolean;
|
|
240
240
|
loading: boolean;
|
|
241
|
-
colorMode: boolean;
|
|
242
241
|
overlay: boolean;
|
|
242
|
+
colorMode: boolean;
|
|
243
243
|
dismissible: boolean;
|
|
244
244
|
fullscreen: boolean;
|
|
245
245
|
modal: boolean;
|
|
@@ -238,8 +238,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
|
|
|
238
238
|
transition: boolean;
|
|
239
239
|
autofocus: boolean;
|
|
240
240
|
loading: boolean;
|
|
241
|
-
colorMode: boolean;
|
|
242
241
|
overlay: boolean;
|
|
242
|
+
colorMode: boolean;
|
|
243
243
|
dismissible: boolean;
|
|
244
244
|
fullscreen: boolean;
|
|
245
245
|
modal: boolean;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { ref, computed, watch, shallowRef, onMounted, onBeforeUnmount, onUnmounted, defineAsyncComponent } from "vue";
|
|
3
|
-
import { useRuntimeConfig, useColorMode } from "#imports";
|
|
3
|
+
import { useRuntimeConfig, useColorMode, useAppConfig } from "#imports";
|
|
4
|
+
import { avatarBorderStyle } from "../../utils/avatarStyle";
|
|
4
5
|
import { useAbracadabra } from "../../composables/useAbracadabra";
|
|
5
6
|
import { useRendererBase } from "../../composables/useRendererBase";
|
|
6
7
|
import { useNodePanel } from "../../composables/useNodePanel";
|
|
@@ -144,6 +145,8 @@ const mapReady = ref(false);
|
|
|
144
145
|
const mapFadedIn = ref(false);
|
|
145
146
|
const colorMode = useColorMode();
|
|
146
147
|
const isDark = computed(() => colorMode.value === "dark");
|
|
148
|
+
const mapAppConfig = useAppConfig();
|
|
149
|
+
const mapNeutralColor = computed(() => mapAppConfig.ui?.colors?.neutral ?? "zinc");
|
|
147
150
|
const activeMode = ref("pan");
|
|
148
151
|
const showLabels = ref(true);
|
|
149
152
|
const popupProvider = shallowRef(null);
|
|
@@ -360,7 +363,15 @@ function createPresenceEl(name, colorHex) {
|
|
|
360
363
|
const el = document.createElement("div");
|
|
361
364
|
el.className = "presence-marker";
|
|
362
365
|
const initials = name.split(" ").map((w) => w[0] ?? "").join("").substring(0, 2).toUpperCase();
|
|
363
|
-
|
|
366
|
+
const avatar = document.createElement("div");
|
|
367
|
+
avatar.className = "presence-avatar";
|
|
368
|
+
avatar.style.cssText = avatarBorderStyle(colorHex, mapNeutralColor.value);
|
|
369
|
+
avatar.textContent = initials;
|
|
370
|
+
const label = document.createElement("div");
|
|
371
|
+
label.className = "presence-label";
|
|
372
|
+
label.textContent = name;
|
|
373
|
+
el.appendChild(avatar);
|
|
374
|
+
el.appendChild(label);
|
|
364
375
|
return el;
|
|
365
376
|
}
|
|
366
377
|
function tickPresenceMarkers() {
|
|
@@ -1620,5 +1631,5 @@ defineExpose({ connectedUsers });
|
|
|
1620
1631
|
</style>
|
|
1621
1632
|
|
|
1622
1633
|
<style>
|
|
1623
|
-
.mapboxgl-map{height:100%!important;width:100%!important}.collab-marker-container{align-items:center;cursor:pointer;display:flex;flex-direction:column}.collab-marker-pin{align-items:center;border-radius:50%;display:flex;height:28px;justify-content:center;transition:transform .2s ease;width:28px;z-index:30}.collab-marker-pin:hover{transform:scale(1.15)}.collab-marker-label{background:rgba(0,0,0,.5);border-radius:3px;color:#fff;font-size:11px;font-weight:700;margin-top:3px;padding:1px 5px;pointer-events:none;text-shadow:0 1px 4px rgba(0,0,0,.7);white-space:nowrap}.collab-line-point{border:2px solid #fff;border-radius:50%;box-shadow:0 1px 4px rgba(0,0,0,.4);cursor:grab;height:10px;width:10px}.collab-line-point:hover{height:14px;width:14px}.presence-marker{align-items:center;display:flex;flex-direction:column;gap:2px;pointer-events:none}.presence-avatar{align-items:center;border
|
|
1634
|
+
.mapboxgl-map{height:100%!important;width:100%!important}.collab-marker-container{align-items:center;cursor:pointer;display:flex;flex-direction:column}.collab-marker-pin{align-items:center;border-radius:50%;display:flex;height:28px;justify-content:center;transition:transform .2s ease;width:28px;z-index:30}.collab-marker-pin:hover{transform:scale(1.15)}.collab-marker-label{background:rgba(0,0,0,.5);border-radius:3px;color:#fff;font-size:11px;font-weight:700;margin-top:3px;padding:1px 5px;pointer-events:none;text-shadow:0 1px 4px rgba(0,0,0,.7);white-space:nowrap}.collab-line-point{border:2px solid #fff;border-radius:50%;box-shadow:0 1px 4px rgba(0,0,0,.4);cursor:grab;height:10px;width:10px}.collab-line-point:hover{height:14px;width:14px}.presence-marker{align-items:center;display:flex;flex-direction:column;gap:2px;pointer-events:none}.presence-avatar{align-items:center;border-radius:50%;box-shadow:0 2px 8px rgba(0,0,0,.4);display:flex;font-size:.65rem;font-weight:700;height:1.75rem;justify-content:center;width:1.75rem}.presence-label{color:#fff;font-size:.6rem;font-weight:700;text-shadow:0 1px 4px rgba(0,0,0,.8);white-space:nowrap}.map-cursor-el{left:0;pointer-events:none;position:absolute;top:0;will-change:transform;z-index:50}.map-cursor-name{font-size:.6rem;font-weight:600;left:14px;top:8px}.map-cursor-name,.measure-label-el{border-radius:3px;color:#000;padding:1px 5px;position:absolute;white-space:nowrap}.measure-label-el{background:rgba(250,204,21,.92);box-shadow:0 1px 4px rgba(0,0,0,.3);font-size:.62rem;font-weight:700;left:0;pointer-events:none;top:0;transform:translate(-50%,calc(-100% - 5px));z-index:35}@keyframes ping-ring{0%{opacity:1;transform:scale(0)}to{opacity:0;transform:scale(3)}}.map-ping-root{height:12px;left:0;pointer-events:none;position:absolute;top:0;transform:translate(-50%,-50%);width:12px;z-index:45}.map-ping-ring{animation:ping-ring 1.5s ease-out forwards;border:3px solid var(--ping-color);border-radius:50%;inset:-16px;position:absolute}.map-ping-dot{background:var(--ping-color);border:2px solid #fff;border-radius:50%;height:12px;left:0;position:absolute;top:0;width:12px}
|
|
1624
1635
|
</style>
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Track list grouped by parent label.
|
|
3
|
-
* Shows equalizer animation for current track, remote listener avatars.
|
|
4
|
-
* Ported from cou-sh/app/components/doc/media/MediaPlaylist.vue
|
|
5
|
-
*/
|
|
6
1
|
import type { MediaTrack, MediaGroup } from '../../../composables/useMediaExtractor.js';
|
|
7
2
|
type __VLS_Props = {
|
|
8
3
|
groups: MediaGroup[];
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { useAppConfig } from "#imports";
|
|
4
|
+
import { avatarBorderStyle } from "../../../utils/avatarStyle";
|
|
2
5
|
const props = defineProps({
|
|
3
6
|
groups: { type: Array, required: true },
|
|
4
7
|
currentTrackId: { type: [String, null], required: true },
|
|
5
8
|
remoteListeners: { type: Array, required: true }
|
|
6
9
|
});
|
|
7
10
|
const emit = defineEmits(["playTrack", "openTrack"]);
|
|
11
|
+
const appConfig = useAppConfig();
|
|
12
|
+
const neutral = computed(() => appConfig.ui?.colors?.neutral ?? "zinc");
|
|
8
13
|
function formatDuration(seconds) {
|
|
9
14
|
if (!seconds || !Number.isFinite(seconds)) return "";
|
|
10
15
|
const m = Math.floor(seconds / 60);
|
|
@@ -89,15 +94,14 @@ function trackSubtitle(track) {
|
|
|
89
94
|
v-if="listenersForTrack(track.id).length"
|
|
90
95
|
class="flex -space-x-1.5 shrink-0 ml-1"
|
|
91
96
|
>
|
|
92
|
-
<
|
|
97
|
+
<UAvatar
|
|
93
98
|
v-for="listener in listenersForTrack(track.id).slice(0, 3)"
|
|
94
99
|
:key="listener.clientId"
|
|
95
|
-
|
|
96
|
-
|
|
100
|
+
:alt="listener.name"
|
|
101
|
+
size="2xs"
|
|
97
102
|
:title="listener.name"
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
</span>
|
|
103
|
+
:style="avatarBorderStyle(listener.color, neutral)"
|
|
104
|
+
/>
|
|
101
105
|
<span
|
|
102
106
|
v-if="listenersForTrack(track.id).length > 3"
|
|
103
107
|
class="size-5 rounded-full flex items-center justify-center text-[9px] font-medium text-(--ui-text-dimmed) bg-(--ui-bg-accented) ring-1 ring-(--ui-bg)"
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Track list grouped by parent label.
|
|
3
|
-
* Shows equalizer animation for current track, remote listener avatars.
|
|
4
|
-
* Ported from cou-sh/app/components/doc/media/MediaPlaylist.vue
|
|
5
|
-
*/
|
|
6
1
|
import type { MediaTrack, MediaGroup } from '../../../composables/useMediaExtractor.js';
|
|
7
2
|
type __VLS_Props = {
|
|
8
3
|
groups: MediaGroup[];
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { useAppConfig } from "#imports";
|
|
4
|
+
import { avatarBorderStyle } from "../../../utils/avatarStyle";
|
|
2
5
|
defineProps({
|
|
3
6
|
isSynced: { type: Boolean, required: true },
|
|
4
7
|
syncedUsers: { type: Array, required: true }
|
|
5
8
|
});
|
|
6
9
|
const emit = defineEmits(["joinSync", "leaveSync"]);
|
|
10
|
+
const appConfig = useAppConfig();
|
|
11
|
+
const neutral = computed(() => appConfig.ui?.colors?.neutral ?? "zinc");
|
|
7
12
|
</script>
|
|
8
13
|
|
|
9
14
|
<template>
|
|
@@ -28,15 +33,14 @@ const emit = defineEmits(["joinSync", "leaveSync"]);
|
|
|
28
33
|
v-if="syncedUsers.length > 0"
|
|
29
34
|
class="flex -space-x-1.5 shrink-0 mr-2"
|
|
30
35
|
>
|
|
31
|
-
<
|
|
36
|
+
<UAvatar
|
|
32
37
|
v-for="user in syncedUsers.slice(0, 5)"
|
|
33
38
|
:key="user.clientId"
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
:alt="user.name"
|
|
40
|
+
size="2xs"
|
|
36
41
|
:title="user.name"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
</span>
|
|
42
|
+
:style="avatarBorderStyle(user.color, neutral)"
|
|
43
|
+
/>
|
|
40
44
|
<span
|
|
41
45
|
v-if="syncedUsers.length > 5"
|
|
42
46
|
class="size-5 rounded-full flex items-center justify-center text-[9px] font-medium text-(--ui-text-dimmed) bg-(--ui-bg-accented) ring-1 ring-(--ui-bg)"
|
|
@@ -12,13 +12,13 @@ type __VLS_Props = {
|
|
|
12
12
|
extraItems?: DropdownMenuItem[][];
|
|
13
13
|
};
|
|
14
14
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
15
|
-
logout: () => any;
|
|
16
15
|
"open-settings": () => any;
|
|
17
16
|
"open-account": () => any;
|
|
17
|
+
logout: () => any;
|
|
18
18
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
19
|
-
onLogout?: (() => any) | undefined;
|
|
20
19
|
"onOpen-settings"?: (() => any) | undefined;
|
|
21
20
|
"onOpen-account"?: (() => any) | undefined;
|
|
21
|
+
onLogout?: (() => any) | undefined;
|
|
22
22
|
}>, {
|
|
23
23
|
color: string;
|
|
24
24
|
collapsed: boolean;
|
|
@@ -12,13 +12,13 @@ type __VLS_Props = {
|
|
|
12
12
|
extraItems?: DropdownMenuItem[][];
|
|
13
13
|
};
|
|
14
14
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
15
|
-
logout: () => any;
|
|
16
15
|
"open-settings": () => any;
|
|
17
16
|
"open-account": () => any;
|
|
17
|
+
logout: () => any;
|
|
18
18
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
19
|
-
onLogout?: (() => any) | undefined;
|
|
20
19
|
"onOpen-settings"?: (() => any) | undefined;
|
|
21
20
|
"onOpen-account"?: (() => any) | undefined;
|
|
21
|
+
onLogout?: (() => any) | undefined;
|
|
22
22
|
}>, {
|
|
23
23
|
color: string;
|
|
24
24
|
collapsed: boolean;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Identity avatar style: neutral background fill, primary foreground (text + icons),
|
|
3
|
+
* split conic border (left half primary, right half neutral) as the identity signal,
|
|
4
|
+
* subtle drop shadow on text/icons for legibility on the neutral fill.
|
|
3
5
|
*
|
|
4
6
|
* CSS rules:
|
|
5
7
|
* - Colors cannot appear in non-final background layers; use linear-gradient(c,c) as a solid-color image instead.
|
|
6
8
|
* - UAvatar has overflow:hidden which clips border-area backgrounds; override with overflow:visible.
|
|
7
|
-
*
|
|
9
|
+
* - `color` cascades to UAvatar's text fallback and to nested UIcon glyphs (UIcon uses currentColor).
|
|
8
10
|
*/
|
|
9
11
|
export declare function avatarBorderStyle(primaryColor: string, neutralColorName: string): string;
|
|
10
12
|
/**
|
|
@@ -2,7 +2,9 @@ export function avatarBorderStyle(primaryColor, neutralColorName) {
|
|
|
2
2
|
const neutral = `var(--color-${neutralColorName}-400, #888)`;
|
|
3
3
|
return [
|
|
4
4
|
"border: 2px solid transparent",
|
|
5
|
-
`background: linear-gradient(${
|
|
5
|
+
`background: linear-gradient(${neutral}, ${neutral}) padding-box, conic-gradient(${primaryColor} 180deg, ${neutral} 180deg) border-box`,
|
|
6
|
+
`color: ${primaryColor} !important`,
|
|
7
|
+
"text-shadow: 0 1px 1px rgba(0, 0, 0, 0.35)",
|
|
6
8
|
"overflow: visible"
|
|
7
9
|
].join("; ");
|
|
8
10
|
}
|
|
@@ -11,7 +13,9 @@ export function avatarStyleFromName(primaryColorName, neutralColorName) {
|
|
|
11
13
|
const neutral = `var(--color-${neutralColorName}-400, #888)`;
|
|
12
14
|
return [
|
|
13
15
|
"border: 2px solid transparent",
|
|
14
|
-
`background: linear-gradient(${
|
|
16
|
+
`background: linear-gradient(${neutral}, ${neutral}) padding-box, conic-gradient(${primary} 180deg, ${neutral} 180deg) border-box`,
|
|
17
|
+
`color: ${primary} !important`,
|
|
18
|
+
"text-shadow: 0 1px 1px rgba(0, 0, 0, 0.35)",
|
|
15
19
|
"overflow: visible"
|
|
16
20
|
].join("; ");
|
|
17
21
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abraca/nuxt",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "First-class Nuxt module for the Abracadabra CRDT collaboration platform",
|
|
5
5
|
"repository": "abracadabra/abracadabra-nuxt",
|
|
6
6
|
"license": "MIT",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|
|
99
|
-
"@abraca/dabra": "^2.0.
|
|
99
|
+
"@abraca/dabra": "^2.0.5",
|
|
100
100
|
"@iconify-json/lucide": "^1.2.105",
|
|
101
101
|
"@noble/ed25519": "^3.1.0",
|
|
102
102
|
"@noble/hashes": "^2.2.0",
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"tslib": "^2.8.1",
|
|
123
123
|
"typescript": "~6.0.3",
|
|
124
124
|
"vitest": "^4.1.5",
|
|
125
|
-
"vue": "^3.5.
|
|
125
|
+
"vue": "^3.5.34",
|
|
126
126
|
"vue-tsc": "^3.2.8",
|
|
127
127
|
"ws": "^8.20.0",
|
|
128
128
|
"yjs": "^13.6.30"
|