@noya-app/noya-multiplayer-react 0.1.43 → 0.1.44
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/.turbo/turbo-build.log +11 -11
- package/CHANGELOG.md +11 -0
- package/dist/index.bundle.js +40 -7
- package/dist/index.d.mts +70 -60
- package/dist/index.d.ts +70 -60
- package/dist/index.js +306 -271
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +313 -278
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -3
- package/src/NoyaStateContext.tsx +163 -13
- package/src/components/UserPointersOverlay.tsx +56 -129
- package/src/hooks.ts +60 -92
- package/src/index.ts +0 -1
- package/src/inspector/StateInspector.tsx +59 -13
- package/src/inspector/useStateInspector.tsx +18 -15
- package/src/noyaApp.ts +20 -12
- package/src/useObservable.ts +54 -7
- package/src/avatarStyle.ts +0 -82
package/src/NoyaStateContext.tsx
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
import { GetAtPath, ObservableOptions, PathKey } from "@noya-app/observable";
|
|
2
1
|
import {
|
|
2
|
+
GetAtPath,
|
|
3
|
+
Observable,
|
|
4
|
+
ObservableOptions,
|
|
5
|
+
PathKey,
|
|
6
|
+
} from "@noya-app/observable";
|
|
7
|
+
import {
|
|
8
|
+
AIManager,
|
|
3
9
|
AssetManager,
|
|
10
|
+
ConnectedUsersManager,
|
|
11
|
+
EphemeralUserDataManager,
|
|
4
12
|
MultiplayerStateManager,
|
|
13
|
+
SecretManager,
|
|
5
14
|
StateManagerOptions,
|
|
6
15
|
Static,
|
|
7
16
|
TSchema,
|
|
17
|
+
WorkflowManager,
|
|
8
18
|
} from "@noya-app/state-manager";
|
|
9
19
|
import React, {
|
|
10
20
|
createContext,
|
|
@@ -16,14 +26,21 @@ import React, {
|
|
|
16
26
|
import { useNoyaState, UseNoyaStateOptions } from "./noyaApp";
|
|
17
27
|
import { useObservable } from "./useObservable";
|
|
18
28
|
|
|
19
|
-
interface NoyaStateProviderProps<S, M, E>
|
|
29
|
+
interface NoyaStateProviderProps<S, M, E extends object>
|
|
20
30
|
extends Omit<UseNoyaStateOptions<S, M, E>, "schema" | "mergeHistoryEntries"> {
|
|
21
31
|
children: React.ReactNode;
|
|
22
32
|
initialState?: S;
|
|
33
|
+
fallback?: React.ReactNode;
|
|
23
34
|
}
|
|
24
35
|
|
|
25
36
|
const AnyNoyaStateContext = createContext<
|
|
26
|
-
| {
|
|
37
|
+
| {
|
|
38
|
+
ms: MultiplayerStateManager<any, any>;
|
|
39
|
+
assetManager: AssetManager;
|
|
40
|
+
workflowManager: WorkflowManager;
|
|
41
|
+
secretManager: SecretManager;
|
|
42
|
+
aiManager: AIManager;
|
|
43
|
+
}
|
|
27
44
|
| undefined
|
|
28
45
|
>(undefined);
|
|
29
46
|
|
|
@@ -64,7 +81,91 @@ export function useAssetManager() {
|
|
|
64
81
|
);
|
|
65
82
|
}
|
|
66
83
|
|
|
67
|
-
export function
|
|
84
|
+
export function useAIManager() {
|
|
85
|
+
const { aiManager } = useAnyNoyaStateContext();
|
|
86
|
+
return aiManager;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function useSecretManager() {
|
|
90
|
+
const { secretManager } = useAnyNoyaStateContext();
|
|
91
|
+
return secretManager;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function useSecrets() {
|
|
95
|
+
const { secretManager } = useAnyNoyaStateContext();
|
|
96
|
+
return useObservable(secretManager.secrets$);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function useSecret(name: string) {
|
|
100
|
+
const { secretManager } = useAnyNoyaStateContext();
|
|
101
|
+
|
|
102
|
+
return useObservable(
|
|
103
|
+
secretManager.secrets$,
|
|
104
|
+
useCallback((secrets) => secrets.find((s) => s.name === name), [name])
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function useIsInitialized() {
|
|
109
|
+
const { ms, secretManager, assetManager } = useAnyNoyaStateContext();
|
|
110
|
+
const isInitializedObservable = useMemo(
|
|
111
|
+
() =>
|
|
112
|
+
Observable.combine(
|
|
113
|
+
[
|
|
114
|
+
ms.isInitialized$,
|
|
115
|
+
secretManager.isInitialized$,
|
|
116
|
+
assetManager.isInitialized$,
|
|
117
|
+
],
|
|
118
|
+
(values) => values.every((v) => v)
|
|
119
|
+
),
|
|
120
|
+
[ms, secretManager, assetManager]
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
return useObservable(isInitializedObservable);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function useWorkflowManager() {
|
|
127
|
+
const { workflowManager } = useAnyNoyaStateContext();
|
|
128
|
+
return workflowManager;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export const ConnectedUsersContext = createContext<
|
|
132
|
+
ConnectedUsersManager | undefined
|
|
133
|
+
>(undefined);
|
|
134
|
+
|
|
135
|
+
export function useConnectedUsersManager() {
|
|
136
|
+
return useContext(ConnectedUsersContext);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export const AnyEphemeralUserDataManagerContext = createContext<
|
|
140
|
+
EphemeralUserDataManager<object> | undefined
|
|
141
|
+
>(undefined);
|
|
142
|
+
|
|
143
|
+
export function useAnyEphemeralUserData() {
|
|
144
|
+
return useContext(AnyEphemeralUserDataManagerContext);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function useCurrentUserId() {
|
|
148
|
+
const connectedUsersManager = useConnectedUsersManager();
|
|
149
|
+
return useObservable(connectedUsersManager?.currentUserId$);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export const FallbackUntilInitialized = ({
|
|
153
|
+
children,
|
|
154
|
+
fallback,
|
|
155
|
+
}: {
|
|
156
|
+
children: React.ReactNode;
|
|
157
|
+
fallback?: React.ReactNode;
|
|
158
|
+
}) => {
|
|
159
|
+
const isInitialized = useIsInitialized();
|
|
160
|
+
|
|
161
|
+
return isInitialized ? children : fallback ?? null;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export function createNoyaContext<
|
|
165
|
+
Schema extends TSchema,
|
|
166
|
+
M = void,
|
|
167
|
+
E extends object = object,
|
|
168
|
+
>({
|
|
68
169
|
schema,
|
|
69
170
|
mergeHistoryEntries,
|
|
70
171
|
}: {
|
|
@@ -80,35 +181,71 @@ export function createNoyaContext<Schema extends TSchema, M = void, E = void>({
|
|
|
80
181
|
| {
|
|
81
182
|
ms: MultiplayerStateManager<S, M>;
|
|
82
183
|
assetManager: AssetManager;
|
|
184
|
+
secretManager: SecretManager;
|
|
83
185
|
}
|
|
84
186
|
| undefined
|
|
85
187
|
>;
|
|
86
188
|
|
|
189
|
+
const EphemeralUserDataManagerContext =
|
|
190
|
+
AnyEphemeralUserDataManagerContext as React.Context<
|
|
191
|
+
EphemeralUserDataManager<E> | undefined
|
|
192
|
+
>;
|
|
193
|
+
|
|
87
194
|
function NoyaStateProvider({
|
|
88
195
|
children,
|
|
89
196
|
initialState,
|
|
90
197
|
...options
|
|
91
198
|
}: NoyaStateProviderProps<S, M, E>) {
|
|
92
|
-
const [
|
|
93
|
-
|
|
199
|
+
const [
|
|
200
|
+
,
|
|
201
|
+
,
|
|
94
202
|
{
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
203
|
+
multiplayerStateManager,
|
|
204
|
+
assetManager,
|
|
205
|
+
workflowManager,
|
|
206
|
+
secretManager,
|
|
207
|
+
aiManager,
|
|
208
|
+
ephemeralUserDataManager,
|
|
209
|
+
connectedUsersManager,
|
|
210
|
+
},
|
|
211
|
+
] = useNoyaState<S, M, E>(initialState, {
|
|
212
|
+
...(options as any),
|
|
213
|
+
schema,
|
|
214
|
+
mergeHistoryEntries,
|
|
215
|
+
});
|
|
100
216
|
|
|
101
217
|
const value = useMemo(
|
|
102
218
|
() => ({
|
|
103
219
|
ms: multiplayerStateManager as MultiplayerStateManager<any, any>,
|
|
104
220
|
assetManager,
|
|
221
|
+
workflowManager,
|
|
222
|
+
secretManager,
|
|
223
|
+
aiManager,
|
|
105
224
|
}),
|
|
106
|
-
[
|
|
225
|
+
[
|
|
226
|
+
multiplayerStateManager,
|
|
227
|
+
assetManager,
|
|
228
|
+
workflowManager,
|
|
229
|
+
secretManager,
|
|
230
|
+
aiManager,
|
|
231
|
+
]
|
|
107
232
|
);
|
|
108
233
|
|
|
109
234
|
return (
|
|
110
235
|
<AnyNoyaStateContext.Provider value={value}>
|
|
111
|
-
{
|
|
236
|
+
<ConnectedUsersContext.Provider value={connectedUsersManager}>
|
|
237
|
+
<EphemeralUserDataManagerContext.Provider
|
|
238
|
+
value={ephemeralUserDataManager}
|
|
239
|
+
>
|
|
240
|
+
{options.fallback !== undefined ? (
|
|
241
|
+
<FallbackUntilInitialized fallback={options.fallback}>
|
|
242
|
+
{children}
|
|
243
|
+
</FallbackUntilInitialized>
|
|
244
|
+
) : (
|
|
245
|
+
children
|
|
246
|
+
)}
|
|
247
|
+
</EphemeralUserDataManagerContext.Provider>
|
|
248
|
+
</ConnectedUsersContext.Provider>
|
|
112
249
|
</AnyNoyaStateContext.Provider>
|
|
113
250
|
);
|
|
114
251
|
}
|
|
@@ -220,6 +357,18 @@ export function createNoyaContext<Schema extends TSchema, M = void, E = void>({
|
|
|
220
357
|
return ms;
|
|
221
358
|
}
|
|
222
359
|
|
|
360
|
+
function useEphemeralUserDataManager() {
|
|
361
|
+
const ephemeralUserData = useContext(EphemeralUserDataManagerContext);
|
|
362
|
+
|
|
363
|
+
if (!ephemeralUserData) {
|
|
364
|
+
throw new Error(
|
|
365
|
+
"useEphemeralUserData must be used within a NoyaStateProvider"
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return ephemeralUserData;
|
|
370
|
+
}
|
|
371
|
+
|
|
223
372
|
return {
|
|
224
373
|
Context: NoyaStateContext,
|
|
225
374
|
Provider: NoyaStateProvider,
|
|
@@ -227,6 +376,7 @@ export function createNoyaContext<Schema extends TSchema, M = void, E = void>({
|
|
|
227
376
|
useSetValue,
|
|
228
377
|
useValueState,
|
|
229
378
|
useStateManager,
|
|
379
|
+
useEphemeralUserDataManager,
|
|
230
380
|
// useAssets,
|
|
231
381
|
// useAssetManager,
|
|
232
382
|
// useAsset,
|
|
@@ -1,132 +1,92 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
3
|
+
import { memoGeneric } from "@noya-app/react-utils";
|
|
4
|
+
import {
|
|
5
|
+
ConnectedUsersManager,
|
|
6
|
+
EphemeralUserDataManager,
|
|
7
|
+
MultiplayerUser,
|
|
8
|
+
} from "@noya-app/state-manager";
|
|
9
|
+
import React, { useEffect, useState } from "react";
|
|
6
10
|
import { useObservable } from "../useObservable";
|
|
7
|
-
|
|
8
11
|
type Point = { x: number; y: number };
|
|
9
12
|
|
|
10
13
|
export type UserPointerData = { pointer?: Point };
|
|
11
14
|
|
|
12
|
-
export type
|
|
15
|
+
export type RenderUserPointerProps = {
|
|
16
|
+
userId: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
visible: boolean;
|
|
19
|
+
point: Point;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type RenderUserPointer = {
|
|
23
|
+
renderUserPointer: (options: RenderUserPointerProps) => React.ReactNode;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type InternalUserPointerProps<E extends UserPointerData> = {
|
|
13
27
|
user: MultiplayerUser;
|
|
14
|
-
|
|
28
|
+
ephemeralUserDataManager: EphemeralUserDataManager<E>;
|
|
15
29
|
hideAfter?: number;
|
|
16
|
-
};
|
|
30
|
+
} & RenderUserPointer;
|
|
17
31
|
|
|
18
32
|
function shouldShow(hideAfter: number, updatedAt: number) {
|
|
19
33
|
return !!updatedAt && Date.now() - updatedAt < hideAfter;
|
|
20
34
|
}
|
|
21
35
|
|
|
22
|
-
const
|
|
36
|
+
const UserPointerInternal = memoGeneric(function UserPointerInternal<
|
|
37
|
+
E extends UserPointerData,
|
|
38
|
+
>({
|
|
23
39
|
user,
|
|
24
|
-
|
|
40
|
+
ephemeralUserDataManager,
|
|
25
41
|
hideAfter = 5000,
|
|
26
|
-
|
|
27
|
-
|
|
42
|
+
renderUserPointer,
|
|
43
|
+
}: InternalUserPointerProps<E>) {
|
|
44
|
+
const metadata = useObservable(ephemeralUserDataManager.metadata$, [
|
|
45
|
+
user.id,
|
|
46
|
+
] as const);
|
|
47
|
+
const data = useObservable(ephemeralUserDataManager.data$, [
|
|
28
48
|
user.id,
|
|
29
49
|
] as const);
|
|
30
|
-
const data = useObservable(ephemeralUserData.data$, [user.id] as const);
|
|
31
|
-
const avatarStyle = useMemo(() => getAvatarStyle(user.id), [user.id]);
|
|
32
50
|
|
|
33
51
|
const [, setForceUpdate] = useState(0);
|
|
34
52
|
|
|
35
53
|
const updatedAt = metadata?.updatedAt ?? 0;
|
|
54
|
+
const show = shouldShow(hideAfter, updatedAt);
|
|
36
55
|
|
|
37
56
|
useEffect(() => {
|
|
38
|
-
if (!
|
|
57
|
+
if (!show) return;
|
|
39
58
|
|
|
40
59
|
const timeoutId = setTimeout(() => {
|
|
41
60
|
setForceUpdate((prev) => prev + 1);
|
|
42
61
|
}, hideAfter);
|
|
43
62
|
|
|
44
63
|
return () => clearTimeout(timeoutId);
|
|
45
|
-
}, [hideAfter, updatedAt]);
|
|
46
|
-
|
|
47
|
-
const show = shouldShow(hideAfter, updatedAt);
|
|
48
|
-
|
|
49
|
-
if (!data || !data.pointer) return null;
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<UserPointerContainer key={user.id} point={data.pointer} show={show}>
|
|
53
|
-
<UserPointerIcon color={avatarStyle.backgroundColor} />
|
|
54
|
-
<UserNameTag background={avatarStyle.backgroundColor}>
|
|
55
|
-
{user.name}
|
|
56
|
-
</UserNameTag>
|
|
57
|
-
</UserPointerContainer>
|
|
58
|
-
);
|
|
59
|
-
};
|
|
64
|
+
}, [hideAfter, show, updatedAt]);
|
|
60
65
|
|
|
61
|
-
|
|
66
|
+
if (!data?.pointer) return null;
|
|
62
67
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
children: React.ReactNode;
|
|
70
|
-
show?: boolean;
|
|
71
|
-
}) {
|
|
72
|
-
return (
|
|
73
|
-
<div
|
|
74
|
-
style={{
|
|
75
|
-
position: "absolute",
|
|
76
|
-
top: 0,
|
|
77
|
-
left: 0,
|
|
78
|
-
transform: `translate(${Math.round(point.x)}px, ${Math.round(
|
|
79
|
-
point.y
|
|
80
|
-
)}px)`,
|
|
81
|
-
opacity: show ? 1 : 0,
|
|
82
|
-
transition: "transform 0.1s, opacity 0.2s",
|
|
83
|
-
}}
|
|
84
|
-
>
|
|
85
|
-
{children}
|
|
86
|
-
</div>
|
|
87
|
-
);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
export const UserNameTag = memo(function UserNameTag({
|
|
91
|
-
background,
|
|
92
|
-
children,
|
|
93
|
-
}: {
|
|
94
|
-
background: string;
|
|
95
|
-
children: React.ReactNode;
|
|
96
|
-
}) {
|
|
97
|
-
return (
|
|
98
|
-
<span
|
|
99
|
-
style={{
|
|
100
|
-
position: "relative",
|
|
101
|
-
top: "8px",
|
|
102
|
-
left: "15px",
|
|
103
|
-
fontSize: 11,
|
|
104
|
-
lineHeight: "1",
|
|
105
|
-
fontWeight: 500,
|
|
106
|
-
boxShadow: "0 1px 1px rgba(0,0,0,0.1)",
|
|
107
|
-
padding: "2px 4px 3px",
|
|
108
|
-
pointerEvents: "none",
|
|
109
|
-
letterSpacing: "-0.3px",
|
|
110
|
-
outline: `1px solid rgba(255,255,255,0.3)`,
|
|
111
|
-
outlineOffset: "-1px",
|
|
112
|
-
background,
|
|
113
|
-
color: "white",
|
|
114
|
-
}}
|
|
115
|
-
>
|
|
116
|
-
{children}
|
|
117
|
-
</span>
|
|
118
|
-
);
|
|
68
|
+
return renderUserPointer({
|
|
69
|
+
userId: user.id,
|
|
70
|
+
name: user.name,
|
|
71
|
+
point: data.pointer,
|
|
72
|
+
visible: show,
|
|
73
|
+
});
|
|
119
74
|
});
|
|
120
75
|
|
|
121
76
|
export type UserPointersOverlayProps<E extends UserPointerData> = {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
};
|
|
77
|
+
connectedUsersManager: ConnectedUsersManager;
|
|
78
|
+
ephemeralUserDataManager: EphemeralUserDataManager<E>;
|
|
79
|
+
} & RenderUserPointer;
|
|
125
80
|
|
|
126
|
-
export const UserPointersOverlay =
|
|
81
|
+
export const UserPointersOverlay = memoGeneric(function UserPointers<
|
|
127
82
|
E extends UserPointerData,
|
|
128
|
-
>({
|
|
129
|
-
|
|
83
|
+
>({
|
|
84
|
+
connectedUsersManager,
|
|
85
|
+
ephemeralUserDataManager,
|
|
86
|
+
renderUserPointer,
|
|
87
|
+
}: UserPointersOverlayProps<E>) {
|
|
88
|
+
const currentUserId = useObservable(ephemeralUserDataManager.currentUserId$);
|
|
89
|
+
const connectedUsers = useObservable(connectedUsersManager.connectedUsers$);
|
|
130
90
|
|
|
131
91
|
return (
|
|
132
92
|
<>
|
|
@@ -134,49 +94,16 @@ export const UserPointersOverlay = memo(function UserPointers<
|
|
|
134
94
|
if (user.id === currentUserId) return null;
|
|
135
95
|
|
|
136
96
|
return (
|
|
137
|
-
<
|
|
97
|
+
<UserPointerInternal
|
|
138
98
|
key={user.id}
|
|
139
99
|
user={user}
|
|
140
|
-
|
|
141
|
-
|
|
100
|
+
ephemeralUserDataManager={
|
|
101
|
+
ephemeralUserDataManager as unknown as EphemeralUserDataManager<UserPointerData>
|
|
142
102
|
}
|
|
103
|
+
renderUserPointer={renderUserPointer}
|
|
143
104
|
/>
|
|
144
105
|
);
|
|
145
106
|
})}
|
|
146
107
|
</>
|
|
147
108
|
);
|
|
148
109
|
});
|
|
149
|
-
|
|
150
|
-
export const UserPointerIcon = memo(function CursorIcon({
|
|
151
|
-
color = "black",
|
|
152
|
-
}: {
|
|
153
|
-
color?: string;
|
|
154
|
-
}) {
|
|
155
|
-
return (
|
|
156
|
-
<svg
|
|
157
|
-
width="15"
|
|
158
|
-
height="15"
|
|
159
|
-
viewBox="0 0 15 15"
|
|
160
|
-
fill="none"
|
|
161
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
162
|
-
style={{
|
|
163
|
-
position: "absolute",
|
|
164
|
-
filter: "drop-shadow(0 1px 1px rgba(0,0,0,0.1))",
|
|
165
|
-
// filter: "drop-shadow(0 1px 1px rgba(0,0,0,0.6))",
|
|
166
|
-
}}
|
|
167
|
-
>
|
|
168
|
-
<path
|
|
169
|
-
fillRule="evenodd"
|
|
170
|
-
clipRule="evenodd"
|
|
171
|
-
d="M3.29227 0.0451998C3.47033 -0.0361222 3.67946 -0.00606629 3.8274 0.122107L12.8587 7.94648C13.0134 8.08054 13.0708 8.29538 13.0035 8.48873C12.9362 8.68208 12.7578 8.81488 12.5533 8.8239L9.21887 8.97096L11.1504 13.2149C11.2648 13.4662 11.1538 13.7626 10.9026 13.877L8.75024 14.8575C8.499 14.972 8.20255 14.8611 8.08802 14.6099L6.15339 10.3665L3.86279 12.7817C3.72196 12.9302 3.50487 12.9779 3.31479 12.9021C3.1247 12.8263 3 12.6423 3 12.4376V0.500008C3 0.304264 3.11422 0.126522 3.29227 0.0451998Z"
|
|
172
|
-
fill={color}
|
|
173
|
-
/>
|
|
174
|
-
<path
|
|
175
|
-
fillRule="evenodd"
|
|
176
|
-
clipRule="evenodd"
|
|
177
|
-
d="M3.29227 0.048984C3.47033 -0.032338 3.67946 -0.00228211 3.8274 0.125891L12.8587 7.95026C13.0134 8.08432 13.0708 8.29916 13.0035 8.49251C12.9362 8.68586 12.7578 8.81866 12.5533 8.82768L9.21887 8.97474L11.1504 13.2187C11.2648 13.47 11.1538 13.7664 10.9026 13.8808L8.75024 14.8613C8.499 14.9758 8.20255 14.8649 8.08802 14.6137L6.15339 10.3703L3.86279 12.7855C3.72196 12.934 3.50487 12.9817 3.31479 12.9059C3.1247 12.8301 3 12.6461 3 12.4414V0.503792C3 0.308048 3.11422 0.130306 3.29227 0.048984ZM4 1.59852V11.1877L5.93799 9.14425C6.05238 9.02363 6.21924 8.96776 6.38319 8.99516C6.54715 9.02256 6.68677 9.12965 6.75573 9.2809L8.79056 13.7441L10.0332 13.178L8.00195 8.71497C7.93313 8.56376 7.94391 8.38824 8.03072 8.24659C8.11753 8.10494 8.26903 8.01566 8.435 8.00834L11.2549 7.88397L4 1.59852Z"
|
|
178
|
-
fill="rgba(255,255,255,0.5)"
|
|
179
|
-
/>
|
|
180
|
-
</svg>
|
|
181
|
-
);
|
|
182
|
-
});
|