@admin-layout/tailwind-ui 12.2.4-alpha.57 → 12.2.4-alpha.59
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/lib/components/AIToolbar/components/completion/AssistantAvatar.d.ts +13 -1
- package/lib/components/AIToolbar/components/completion/AssistantAvatar.d.ts.map +1 -1
- package/lib/components/AIToolbar/components/completion/AssistantAvatar.js +17 -5
- package/lib/components/AIToolbar/components/completion/AssistantAvatar.js.map +1 -1
- package/lib/components/AIToolbar/components/completion/Input.d.ts.map +1 -1
- package/lib/components/AIToolbar/components/completion/Input.js +6 -2
- package/lib/components/AIToolbar/components/completion/Input.js.map +1 -1
- package/lib/components/AIToolbar/components/completion/MessageHistory.d.ts.map +1 -1
- package/lib/components/AIToolbar/components/completion/MessageHistory.js +3 -1
- package/lib/components/AIToolbar/components/completion/MessageHistory.js.map +1 -1
- package/lib/components/AIToolbar/hooks/useActiveCharacter.d.ts +2 -2
- package/lib/components/AIToolbar/hooks/useActiveCharacter.d.ts.map +1 -1
- package/lib/components/AIToolbar/hooks/useActiveCharacter.js +94 -62
- package/lib/components/AIToolbar/hooks/useActiveCharacter.js.map +1 -1
- package/lib/components/AIToolbar/hooks/useCharacterSprite.d.ts +14 -0
- package/lib/components/AIToolbar/hooks/useCharacterSprite.d.ts.map +1 -0
- package/lib/components/AIToolbar/hooks/useCharacterSprite.js +103 -0
- package/lib/components/AIToolbar/hooks/useCharacterSprite.js.map +1 -0
- package/lib/components/AIToolbar/utils/emotionClassifier.d.ts +19 -0
- package/lib/components/AIToolbar/utils/emotionClassifier.d.ts.map +1 -0
- package/lib/components/AIToolbar/utils/emotionClassifier.js +142 -0
- package/lib/components/AIToolbar/utils/emotionClassifier.js.map +1 -0
- package/lib/hooks/activeCharacterPreference.d.ts +24 -0
- package/lib/hooks/activeCharacterPreference.d.ts.map +1 -0
- package/lib/hooks/activeCharacterPreference.js +64 -0
- package/lib/hooks/activeCharacterPreference.js.map +1 -0
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
interface AssistantAvatarProps {
|
|
2
|
+
/** Static fallback avatar (default portrait). Used when no sprite is resolved. */
|
|
2
3
|
avatarSrc: string | null;
|
|
3
4
|
/** Optional message sequence number rendered as "#N" beneath the avatar. */
|
|
4
5
|
index?: number;
|
|
@@ -6,7 +7,18 @@ interface AssistantAvatarProps {
|
|
|
6
7
|
size?: number;
|
|
7
8
|
/** Tailwind classes applied to the column wrapper. */
|
|
8
9
|
className?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Character `file_name` (i.e. the PNG card stem — "Seraphina"). When set
|
|
12
|
+
* together with `text`, the avatar switches to the matching expression
|
|
13
|
+
* sprite from the character's sprite folder.
|
|
14
|
+
*/
|
|
15
|
+
characterFileName?: string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Message text used to pick an emotion sprite. The classifier maps the
|
|
18
|
+
* text to one of 28 GoEmotions labels (`neutral`, `joy`, `caring`, ...).
|
|
19
|
+
*/
|
|
20
|
+
text?: string | null;
|
|
9
21
|
}
|
|
10
|
-
export declare function AssistantAvatar({ avatarSrc, index, size, className }: AssistantAvatarProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export declare function AssistantAvatar({ avatarSrc, index, size, className, characterFileName, text, }: AssistantAvatarProps): import("react/jsx-runtime").JSX.Element;
|
|
11
23
|
export default AssistantAvatar;
|
|
12
24
|
//# sourceMappingURL=AssistantAvatar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantAvatar.d.ts","sourceRoot":"","sources":["../../../../../src/components/AIToolbar/components/completion/AssistantAvatar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AssistantAvatar.d.ts","sourceRoot":"","sources":["../../../../../src/components/AIToolbar/components/completion/AssistantAvatar.tsx"],"names":[],"mappings":"AAgBA,UAAU,oBAAoB;IAC1B,kFAAkF;IAClF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,wBAAgB,eAAe,CAAC,EAC5B,SAAS,EACT,KAAK,EACL,IAAS,EACT,SAAS,EACT,iBAAiB,EACjB,IAAI,GACP,EAAE,oBAAoB,2CA2CtB;AAED,eAAe,eAAe,CAAC"}
|
|
@@ -1,15 +1,27 @@
|
|
|
1
|
-
import {jsxs,jsx}from'react/jsx-runtime';import'../../../../utils/isBrowser/index.js';import {cn}from'../../../../utils/util.js';import'
|
|
1
|
+
import {jsxs,jsx}from'react/jsx-runtime';import*as React from'react';import'../../../../utils/isBrowser/index.js';import {cn}from'../../../../utils/util.js';import'fast-deep-equal/react.js';import {useCharacterSprite}from'../../hooks/useCharacterSprite.js';import {classifyEmotion}from'../../utils/emotionClassifier.js';function AssistantAvatar({
|
|
2
2
|
avatarSrc,
|
|
3
3
|
index,
|
|
4
|
-
size =
|
|
5
|
-
className
|
|
4
|
+
size = 60,
|
|
5
|
+
className,
|
|
6
|
+
characterFileName,
|
|
7
|
+
text
|
|
6
8
|
}) {
|
|
7
9
|
const hasNumber = typeof index === 'number';
|
|
10
|
+
// Pick an emotion only when we actually have a character that can supply
|
|
11
|
+
// a sprite — avoids burning a Tauri round-trip for non-Tauri builds.
|
|
12
|
+
const emotion = React.useMemo(() => {
|
|
13
|
+
if (!characterFileName || !text) return null;
|
|
14
|
+
return classifyEmotion(text);
|
|
15
|
+
}, [characterFileName, text]);
|
|
16
|
+
const spriteSrc = useCharacterSprite(characterFileName ?? null, emotion);
|
|
17
|
+
// Prefer the emotion sprite; fall back to the static avatar while it loads
|
|
18
|
+
// or when sprite resolution returned null (no character / outside Tauri).
|
|
19
|
+
const renderedSrc = spriteSrc ?? avatarSrc;
|
|
8
20
|
return jsxs("div", {
|
|
9
21
|
className: cn('flex shrink-0 flex-col items-center gap-1 pt-0.5', className),
|
|
10
22
|
"aria-hidden": !hasNumber,
|
|
11
|
-
children: [
|
|
12
|
-
src:
|
|
23
|
+
children: [renderedSrc ? jsx("img", {
|
|
24
|
+
src: renderedSrc,
|
|
13
25
|
alt: "",
|
|
14
26
|
"aria-hidden": "true",
|
|
15
27
|
draggable: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantAvatar.js","sources":["../../../../../src/components/AIToolbar/components/completion/AssistantAvatar.tsx"],"sourcesContent":[null],"names":[
|
|
1
|
+
{"version":3,"file":"AssistantAvatar.js","sources":["../../../../../src/components/AIToolbar/components/completion/AssistantAvatar.tsx"],"sourcesContent":[null],"names":[],"mappings":"gUA+BI,SAAA,eAAA,CAAA;;;AAGG,EAAA,IAAA,GAAA,EAAA;AACH,EAAA,SAAO;AACV,EAAA,iBAAA;AAED,EAAA;AAoDA,CAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../../../../src/components/AIToolbar/components/completion/Input.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAQ/C,eAAO,MAAM,KAAK,GAAI,sTAsBnB,mBAAmB,GAAG;IACrB,QAAQ,EAAE,OAAO,CAAC;CACrB,
|
|
1
|
+
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../../../../src/components/AIToolbar/components/completion/Input.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAQ/C,eAAO,MAAM,KAAK,GAAI,sTAsBnB,mBAAmB,GAAG;IACrB,QAAQ,EAAE,OAAO,CAAC;CACrB,4CA6TA,CAAC"}
|
|
@@ -178,7 +178,9 @@ import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {useRef,useMemo,useLayo
|
|
|
178
178
|
className: "flex w-full gap-3",
|
|
179
179
|
children: [jsx(AssistantAvatar, {
|
|
180
180
|
avatarSrc: character?.avatarSrc ?? null,
|
|
181
|
-
index: idx + 1
|
|
181
|
+
index: idx + 1,
|
|
182
|
+
characterFileName: character?.fileName ?? null,
|
|
183
|
+
text: msg.content
|
|
182
184
|
}), jsxs("div", {
|
|
183
185
|
className: "min-w-0 flex-1",
|
|
184
186
|
children: [jsxs("div", {
|
|
@@ -211,7 +213,9 @@ import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {useRef,useMemo,useLayo
|
|
|
211
213
|
className: "flex w-full gap-3",
|
|
212
214
|
children: [jsx(AssistantAvatar, {
|
|
213
215
|
avatarSrc: character?.avatarSrc ?? null,
|
|
214
|
-
index: sortedAsc.length + 1
|
|
216
|
+
index: sortedAsc.length + 1,
|
|
217
|
+
characterFileName: character?.fileName ?? null,
|
|
218
|
+
text: response
|
|
215
219
|
}), jsxs("div", {
|
|
216
220
|
className: "min-w-0 flex-1",
|
|
217
221
|
children: [jsxs("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Input.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageHistory.d.ts","sourceRoot":"","sources":["../../../../../src/components/AIToolbar/components/completion/MessageHistory.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAM5C,UAAU,mBAAmB;IACzB,mBAAmB,EAAE,WAAW,EAAE,CAAC;IACnC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,sBAAsB,EAAE,MAAM,IAAI,CAAC;IACnC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAClD;AAED,eAAO,MAAM,cAAc,GAAI,6FAK5B,mBAAmB,
|
|
1
|
+
{"version":3,"file":"MessageHistory.d.ts","sourceRoot":"","sources":["../../../../../src/components/AIToolbar/components/completion/MessageHistory.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAM5C,UAAU,mBAAmB;IACzB,mBAAmB,EAAE,WAAW,EAAE,CAAC;IACnC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,sBAAsB,EAAE,MAAM,IAAI,CAAC;IACnC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAClD;AAED,eAAO,MAAM,cAAc,GAAI,6FAK5B,mBAAmB,4CAyIrB,CAAC"}
|
|
@@ -101,7 +101,9 @@ import {jsxs,jsx,Fragment}from'react/jsx-runtime';import {MessageSquareText,Chev
|
|
|
101
101
|
className: "flex w-full gap-3",
|
|
102
102
|
children: [jsx(AssistantAvatar, {
|
|
103
103
|
avatarSrc: character?.avatarSrc ?? null,
|
|
104
|
-
index: arr.length - descIdx
|
|
104
|
+
index: arr.length - descIdx,
|
|
105
|
+
characterFileName: character?.fileName ?? null,
|
|
106
|
+
text: message.content
|
|
105
107
|
}), jsxs("div", {
|
|
106
108
|
className: "min-w-0 flex-1",
|
|
107
109
|
children: [jsxs("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageHistory.js","sources":["../../../../../src/components/AIToolbar/components/completion/MessageHistory.tsx"],"sourcesContent":[null],"names":[],"mappings":"i1EAcC,MAAA,cAAA,GAAA,CAAA;AAED,EAAA,mBAAa
|
|
1
|
+
{"version":3,"file":"MessageHistory.js","sources":["../../../../../src/components/AIToolbar/components/completion/MessageHistory.tsx"],"sourcesContent":[null],"names":[],"mappings":"i1EAcC,MAAA,cAAA,GAAA,CAAA;AAED,EAAA,mBAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -21,8 +21,8 @@ export interface CharacterPicker {
|
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Return the active character (name + avatar) or null when none is installed
|
|
24
|
-
* / we're not running under Tauri. Selection
|
|
25
|
-
*
|
|
24
|
+
* / we're not running under Tauri. Selection follows `pickActiveMerged` (file_name
|
|
25
|
+
* pref, then name pref) and stays in sync with `useCharacterPicker` / desktop settings.
|
|
26
26
|
*/
|
|
27
27
|
export declare function useActiveCharacter(): ActiveCharacter | null;
|
|
28
28
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useActiveCharacter.d.ts","sourceRoot":"","sources":["../../../../src/components/AIToolbar/hooks/useActiveCharacter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useActiveCharacter.d.ts","sourceRoot":"","sources":["../../../../src/components/AIToolbar/hooks/useActiveCharacter.ts"],"names":[],"mappings":"AAqCA,MAAM,WAAW,eAAe;IAC5B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC5B,sDAAsD;IACtD,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,gFAAgF;IAChF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iFAAiF;IACjF,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC5C;AAmMD;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,IAAI,CAkC3D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CAiEpD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import*as React from'react';// Active-character lookup for the AIToolbar.
|
|
1
|
+
import*as React from'react';import {ACTIVE_CHARACTER_CHANGE_EVENT,readPreferredActiveCharacterFileName,setPreferredActiveCharacterFileName,ACTIVE_CHARACTER_FILE_NAME_STORAGE_KEY}from'../../../hooks/activeCharacterPreference.js';import {clearCharacterSpriteCache}from'./useCharacterSprite.js';// Active-character lookup for the AIToolbar.
|
|
2
2
|
//
|
|
3
3
|
// Surfaces the currently-selected character (name + avatar data URL) so the
|
|
4
4
|
// completion popover and message history can show "Seraphina" with her avatar
|
|
@@ -12,11 +12,17 @@ import*as React from'react';// Active-character lookup for the AIToolbar.
|
|
|
12
12
|
// - Tauri with an extension but no avatar: returns name-only (avatarSrc = null).
|
|
13
13
|
//
|
|
14
14
|
// Re-fetches on the `yantra:character-refresh` Tauri event + the
|
|
15
|
-
// `yantra:extensions-changed` window event (marketplace install/uninstall)
|
|
15
|
+
// `yantra:extensions-changed` window event (marketplace install/uninstall), and
|
|
16
|
+
// re-resolves when either persisted preference changes:
|
|
17
|
+
// - `yantra:active-character-name` (name-based — CharacterPicker / toolbar), and/or
|
|
18
|
+
// - `yantra:active-character:file-name` + `yantra:active-character-change` (file_name
|
|
19
|
+
// + cross-webview emit — desktop settings / `activeCharacterPreference.ts`).
|
|
16
20
|
//
|
|
17
|
-
// When multiple characters are installed,
|
|
18
|
-
//
|
|
19
|
-
//
|
|
21
|
+
// When multiple characters are installed, resolution order is: **file_name**
|
|
22
|
+
// preference first (so the dashboard bar and main app stay aligned), then
|
|
23
|
+
// **name** preference (`yantra:active-character-name`), then `character_list[0]`.
|
|
24
|
+
// Use `useCharacterPicker` to enumerate and switch by name (it also syncs
|
|
25
|
+
// the file_name preference + Tauri fan-out).
|
|
20
26
|
// constants
|
|
21
27
|
const CHARACTER_REFRESH_EVENT = 'yantra:character-refresh';
|
|
22
28
|
/**
|
|
@@ -91,62 +97,111 @@ async function fetchAvatarSrc(fileName) {
|
|
|
91
97
|
if (!dto || !dto.base64 || dto.base64.length <= 100) return null;
|
|
92
98
|
return `data:${dto.mime_type || 'image/png'};base64,${dto.base64}`;
|
|
93
99
|
}
|
|
94
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Choose the active row: **file_name** preference (desktop settings / cross-webview),
|
|
102
|
+
* else **name** preference (toolbar picker), else first in list.
|
|
103
|
+
*/
|
|
104
|
+
function pickActiveMerged(list) {
|
|
95
105
|
if (list.length === 0) return null;
|
|
106
|
+
const filePref = readPreferredActiveCharacterFileName();
|
|
107
|
+
if (filePref) {
|
|
108
|
+
const byFile = list.find(c => c.file_name === filePref);
|
|
109
|
+
if (byFile) return byFile;
|
|
110
|
+
}
|
|
111
|
+
const desiredName = readStoredActiveName();
|
|
96
112
|
if (desiredName) {
|
|
97
|
-
const
|
|
98
|
-
if (
|
|
113
|
+
const byName = list.find(c => c.name === desiredName);
|
|
114
|
+
if (byName) return byName;
|
|
99
115
|
}
|
|
100
116
|
return list[0];
|
|
101
117
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
*/
|
|
108
|
-
function useActiveCharacter() {
|
|
109
|
-
const [list, setList] = React.useState([]);
|
|
110
|
-
const [activeName, setActiveName] = React.useState(() => readStoredActiveName());
|
|
111
|
-
const [avatarSrc, setAvatarSrc] = React.useState(null);
|
|
112
|
-
const reload = React.useCallback(async () => {
|
|
113
|
-
const next = await safeInvoke('character_list', {
|
|
114
|
-
shallow: false
|
|
115
|
-
});
|
|
116
|
-
setList(next ?? []);
|
|
118
|
+
/** Subscribe to both preference schemes + cross-webview Tauri event; bump resets derived selection. */
|
|
119
|
+
function usePreferenceSyncBump() {
|
|
120
|
+
const [bump, setBump] = React.useState(0);
|
|
121
|
+
const bumpFn = React.useCallback(() => {
|
|
122
|
+
setBump(n => n + 1);
|
|
117
123
|
}, []);
|
|
124
|
+
return [bump, bumpFn];
|
|
125
|
+
}
|
|
126
|
+
function useCharacterPreferenceListeners(reload, bump) {
|
|
118
127
|
React.useEffect(() => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
React.useEffect(() => {
|
|
122
|
-
let unlisten = null;
|
|
128
|
+
let unlistenChar = null;
|
|
129
|
+
let unlistenFilePref = null;
|
|
123
130
|
let cancelled = false;
|
|
124
131
|
safeListen(CHARACTER_REFRESH_EVENT, () => {
|
|
132
|
+
clearCharacterSpriteCache();
|
|
125
133
|
void reload();
|
|
134
|
+
bump();
|
|
135
|
+
}).then(fn => {
|
|
136
|
+
if (cancelled) fn();else unlistenChar = fn;
|
|
137
|
+
});
|
|
138
|
+
safeListen(ACTIVE_CHARACTER_CHANGE_EVENT, () => {
|
|
139
|
+
clearCharacterSpriteCache();
|
|
140
|
+
bump();
|
|
126
141
|
}).then(fn => {
|
|
127
|
-
if (cancelled) fn();else
|
|
142
|
+
if (cancelled) fn();else unlistenFilePref = fn;
|
|
128
143
|
});
|
|
129
144
|
function onExtensionsChanged(e) {
|
|
130
145
|
if (!isCharacterRelevant(e)) return;
|
|
146
|
+
clearCharacterSpriteCache();
|
|
131
147
|
void reload();
|
|
148
|
+
bump();
|
|
132
149
|
}
|
|
133
150
|
function onActiveChanged() {
|
|
134
|
-
|
|
151
|
+
clearCharacterSpriteCache();
|
|
152
|
+
bump();
|
|
153
|
+
}
|
|
154
|
+
function onFilePrefLocal(e) {
|
|
155
|
+
clearCharacterSpriteCache();
|
|
156
|
+
bump();
|
|
157
|
+
}
|
|
158
|
+
function onStorageKey(ev) {
|
|
159
|
+
if (ev.key !== ACTIVE_CHARACTER_STORAGE_KEY && ev.key !== ACTIVE_CHARACTER_FILE_NAME_STORAGE_KEY && ev.key != null) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
clearCharacterSpriteCache();
|
|
163
|
+
bump();
|
|
135
164
|
}
|
|
136
165
|
if (typeof window !== 'undefined') {
|
|
137
166
|
window.addEventListener(EXTENSIONS_CHANGED_EVENT, onExtensionsChanged);
|
|
138
167
|
window.addEventListener(ACTIVE_CHARACTER_CHANGED_EVENT, onActiveChanged);
|
|
168
|
+
window.addEventListener(ACTIVE_CHARACTER_CHANGE_EVENT, onFilePrefLocal);
|
|
169
|
+
window.addEventListener('storage', onStorageKey);
|
|
139
170
|
}
|
|
140
171
|
return () => {
|
|
141
172
|
cancelled = true;
|
|
142
|
-
if (
|
|
173
|
+
if (unlistenChar) unlistenChar();
|
|
174
|
+
if (unlistenFilePref) unlistenFilePref();
|
|
143
175
|
if (typeof window !== 'undefined') {
|
|
144
176
|
window.removeEventListener(EXTENSIONS_CHANGED_EVENT, onExtensionsChanged);
|
|
145
177
|
window.removeEventListener(ACTIVE_CHARACTER_CHANGED_EVENT, onActiveChanged);
|
|
178
|
+
window.removeEventListener(ACTIVE_CHARACTER_CHANGE_EVENT, onFilePrefLocal);
|
|
179
|
+
window.removeEventListener('storage', onStorageKey);
|
|
146
180
|
}
|
|
147
181
|
};
|
|
182
|
+
}, [reload, bump]);
|
|
183
|
+
}
|
|
184
|
+
// main API
|
|
185
|
+
/**
|
|
186
|
+
* Return the active character (name + avatar) or null when none is installed
|
|
187
|
+
* / we're not running under Tauri. Selection follows `pickActiveMerged` (file_name
|
|
188
|
+
* pref, then name pref) and stays in sync with `useCharacterPicker` / desktop settings.
|
|
189
|
+
*/
|
|
190
|
+
function useActiveCharacter() {
|
|
191
|
+
const [list, setList] = React.useState([]);
|
|
192
|
+
const [avatarSrc, setAvatarSrc] = React.useState(null);
|
|
193
|
+
const [bump, bumpFn] = usePreferenceSyncBump();
|
|
194
|
+
const reload = React.useCallback(async () => {
|
|
195
|
+
const next = await safeInvoke('character_list', {
|
|
196
|
+
shallow: false
|
|
197
|
+
});
|
|
198
|
+
setList(next ?? []);
|
|
199
|
+
}, []);
|
|
200
|
+
React.useEffect(() => {
|
|
201
|
+
void reload();
|
|
148
202
|
}, [reload]);
|
|
149
|
-
|
|
203
|
+
useCharacterPreferenceListeners(reload, bumpFn);
|
|
204
|
+
const active = React.useMemo(() => pickActiveMerged(list), [list, bump]);
|
|
150
205
|
React.useEffect(() => {
|
|
151
206
|
if (!active?.file_name) {
|
|
152
207
|
setAvatarSrc(null);
|
|
@@ -174,7 +229,7 @@ function useActiveCharacter() {
|
|
|
174
229
|
function useCharacterPicker() {
|
|
175
230
|
const [list, setList] = React.useState([]);
|
|
176
231
|
const [avatars, setAvatars] = React.useState({});
|
|
177
|
-
const [
|
|
232
|
+
const [bump, bumpFn] = usePreferenceSyncBump();
|
|
178
233
|
const reload = React.useCallback(async () => {
|
|
179
234
|
const next = await safeInvoke('character_list', {
|
|
180
235
|
shallow: false
|
|
@@ -184,34 +239,8 @@ function useCharacterPicker() {
|
|
|
184
239
|
React.useEffect(() => {
|
|
185
240
|
void reload();
|
|
186
241
|
}, [reload]);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
let cancelled = false;
|
|
190
|
-
safeListen(CHARACTER_REFRESH_EVENT, () => {
|
|
191
|
-
void reload();
|
|
192
|
-
}).then(fn => {
|
|
193
|
-
if (cancelled) fn();else unlisten = fn;
|
|
194
|
-
});
|
|
195
|
-
function onExtensionsChanged(e) {
|
|
196
|
-
if (!isCharacterRelevant(e)) return;
|
|
197
|
-
void reload();
|
|
198
|
-
}
|
|
199
|
-
function onActiveChanged() {
|
|
200
|
-
setActiveNameState(readStoredActiveName());
|
|
201
|
-
}
|
|
202
|
-
if (typeof window !== 'undefined') {
|
|
203
|
-
window.addEventListener(EXTENSIONS_CHANGED_EVENT, onExtensionsChanged);
|
|
204
|
-
window.addEventListener(ACTIVE_CHARACTER_CHANGED_EVENT, onActiveChanged);
|
|
205
|
-
}
|
|
206
|
-
return () => {
|
|
207
|
-
cancelled = true;
|
|
208
|
-
if (unlisten) unlisten();
|
|
209
|
-
if (typeof window !== 'undefined') {
|
|
210
|
-
window.removeEventListener(EXTENSIONS_CHANGED_EVENT, onExtensionsChanged);
|
|
211
|
-
window.removeEventListener(ACTIVE_CHARACTER_CHANGED_EVENT, onActiveChanged);
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
}, [reload]);
|
|
242
|
+
useCharacterPreferenceListeners(reload, bumpFn);
|
|
243
|
+
const activeName = React.useMemo(() => pickActiveMerged(list)?.name ?? null, [list, bump]);
|
|
215
244
|
// Resolve avatars for every character in the list (cached by file_name).
|
|
216
245
|
React.useEffect(() => {
|
|
217
246
|
let alive = true;
|
|
@@ -240,7 +269,10 @@ function useCharacterPicker() {
|
|
|
240
269
|
})), [list, avatars]);
|
|
241
270
|
const setActive = React.useCallback(name => {
|
|
242
271
|
writeStoredActiveName(name);
|
|
243
|
-
|
|
272
|
+
const row = name ? list.find(c => c.name === name) : null;
|
|
273
|
+
void setPreferredActiveCharacterFileName(row?.file_name ?? null);
|
|
274
|
+
clearCharacterSpriteCache();
|
|
275
|
+
bumpFn();
|
|
244
276
|
if (typeof window !== 'undefined') {
|
|
245
277
|
window.dispatchEvent(new CustomEvent(ACTIVE_CHARACTER_CHANGED_EVENT, {
|
|
246
278
|
detail: {
|
|
@@ -248,7 +280,7 @@ function useCharacterPicker() {
|
|
|
248
280
|
}
|
|
249
281
|
}));
|
|
250
282
|
}
|
|
251
|
-
}, []);
|
|
283
|
+
}, [list, bumpFn]);
|
|
252
284
|
return {
|
|
253
285
|
characters,
|
|
254
286
|
activeName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useActiveCharacter.js","sources":["../../../../src/components/AIToolbar/hooks/useActiveCharacter.ts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useActiveCharacter.js","sources":["../../../../src/components/AIToolbar/hooks/useActiveCharacter.ts"],"sourcesContent":[null],"names":[],"mappings":"oSAqCA;;;;;;AAMI;AACH;AAED;;;AAGI;AACH;AAED;;;;AAII;;;AAGH;AAmMD;;;;;;AA4CG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the data URL for `(characterFileName, label)` or `null` while the
|
|
3
|
+
* sprite is loading / when running outside Tauri / when no character is set.
|
|
4
|
+
*
|
|
5
|
+
* Re-evaluates whenever either input changes. Cached results resolve in the
|
|
6
|
+
* same render (no transient `null`).
|
|
7
|
+
*/
|
|
8
|
+
export declare function useCharacterSprite(characterFileName: string | null | undefined, label: string | null | undefined): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Clears the sprite cache. Call after `character_refresh` so newly-installed
|
|
11
|
+
* sprite packs aren't shadowed by stale data URLs.
|
|
12
|
+
*/
|
|
13
|
+
export declare function clearCharacterSpriteCache(): void;
|
|
14
|
+
//# sourceMappingURL=useCharacterSprite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCharacterSprite.d.ts","sourceRoot":"","sources":["../../../../src/components/AIToolbar/hooks/useCharacterSprite.ts"],"names":[],"mappings":"AAqFA;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAC9B,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC5C,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACjC,MAAM,GAAG,IAAI,CAoBf;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAGhD"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import*as React from'react';// Expression-sprite lookup for assistant message bubbles.
|
|
2
|
+
//
|
|
3
|
+
// Resolves `(characterFileName, label)` → `data:image/png;base64,...` via the
|
|
4
|
+
// Tauri command `character_get_expression`, with a module-level cache so the
|
|
5
|
+
// same sprite is fetched at most once per session even when many messages map
|
|
6
|
+
// to the same emotion.
|
|
7
|
+
//
|
|
8
|
+
// The Rust side (`character_get_expression`) already implements graceful
|
|
9
|
+
// fallback through `neutral`/`joy`/avatar when the requested label is missing,
|
|
10
|
+
// so callers can pass any of the 28 GoEmotions labels without first checking
|
|
11
|
+
// which sprites the character actually ships.
|
|
12
|
+
//
|
|
13
|
+
// Degrades to `null` outside Tauri / when no character file_name is provided.
|
|
14
|
+
function isTauri() {
|
|
15
|
+
if (typeof window === 'undefined') return false;
|
|
16
|
+
const w = window;
|
|
17
|
+
return Boolean(w.__TAURI_INTERNALS__ ?? w.__TAURI__);
|
|
18
|
+
}
|
|
19
|
+
async function safeInvoke(cmd, args) {
|
|
20
|
+
if (!isTauri()) return null;
|
|
21
|
+
try {
|
|
22
|
+
// @ts-ignore — optional dynamic import, present as a peer dep in Tauri builds.
|
|
23
|
+
const mod = await import('@tauri-apps/api/core');
|
|
24
|
+
return await mod.invoke(cmd, args);
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Two layered caches keyed by `${fileName}::${label}`:
|
|
30
|
+
//
|
|
31
|
+
// - `urlCache` resolves synchronously on subsequent calls (no re-render flicker).
|
|
32
|
+
// - `pendingCache` deduplicates concurrent fetches for the same key when
|
|
33
|
+
// several messages on screen happen to share the same emotion.
|
|
34
|
+
const urlCache = new Map();
|
|
35
|
+
const pendingCache = new Map();
|
|
36
|
+
function cacheKey(fileName, label) {
|
|
37
|
+
return `${fileName}::${label}`;
|
|
38
|
+
}
|
|
39
|
+
async function fetchSprite(fileName, label) {
|
|
40
|
+
const key = cacheKey(fileName, label);
|
|
41
|
+
const cached = urlCache.get(key);
|
|
42
|
+
if (cached !== undefined) return cached;
|
|
43
|
+
const pending = pendingCache.get(key);
|
|
44
|
+
if (pending) return pending;
|
|
45
|
+
const promise = (async () => {
|
|
46
|
+
const dto = await safeInvoke('character_get_expression', {
|
|
47
|
+
fileName,
|
|
48
|
+
label
|
|
49
|
+
});
|
|
50
|
+
if (!dto || !dto.base64 || dto.base64.length < 100) {
|
|
51
|
+
urlCache.set(key, '');
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const url = `data:${dto.mime_type || 'image/png'};base64,${dto.base64}`;
|
|
55
|
+
urlCache.set(key, url);
|
|
56
|
+
// If Rust fell back to a different label (sprite missing), also cache
|
|
57
|
+
// the resolved label so a subsequent call for it short-circuits.
|
|
58
|
+
if (dto.label && dto.label !== label) {
|
|
59
|
+
urlCache.set(cacheKey(fileName, dto.label), url);
|
|
60
|
+
}
|
|
61
|
+
return url;
|
|
62
|
+
})();
|
|
63
|
+
pendingCache.set(key, promise);
|
|
64
|
+
try {
|
|
65
|
+
return await promise;
|
|
66
|
+
} finally {
|
|
67
|
+
pendingCache.delete(key);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Returns the data URL for `(characterFileName, label)` or `null` while the
|
|
72
|
+
* sprite is loading / when running outside Tauri / when no character is set.
|
|
73
|
+
*
|
|
74
|
+
* Re-evaluates whenever either input changes. Cached results resolve in the
|
|
75
|
+
* same render (no transient `null`).
|
|
76
|
+
*/
|
|
77
|
+
function useCharacterSprite(characterFileName, label) {
|
|
78
|
+
const key = characterFileName && label ? cacheKey(characterFileName, label) : null;
|
|
79
|
+
const cachedInitial = key ? urlCache.get(key) ?? null : null;
|
|
80
|
+
const [src, setSrc] = React.useState(cachedInitial && cachedInitial !== '' ? cachedInitial : null);
|
|
81
|
+
React.useEffect(() => {
|
|
82
|
+
if (!characterFileName || !label) {
|
|
83
|
+
setSrc(null);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
let alive = true;
|
|
87
|
+
fetchSprite(characterFileName, label).then(url => {
|
|
88
|
+
if (alive) setSrc(url);
|
|
89
|
+
});
|
|
90
|
+
return () => {
|
|
91
|
+
alive = false;
|
|
92
|
+
};
|
|
93
|
+
}, [characterFileName, label]);
|
|
94
|
+
return src;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Clears the sprite cache. Call after `character_refresh` so newly-installed
|
|
98
|
+
* sprite packs aren't shadowed by stale data URLs.
|
|
99
|
+
*/
|
|
100
|
+
function clearCharacterSpriteCache() {
|
|
101
|
+
urlCache.clear();
|
|
102
|
+
pendingCache.clear();
|
|
103
|
+
}export{clearCharacterSpriteCache,useCharacterSprite};//# sourceMappingURL=useCharacterSprite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCharacterSprite.js","sources":["../../../../src/components/AIToolbar/hooks/useCharacterSprite.ts"],"sourcesContent":[null],"names":[],"mappings":"4BAqFA;;;;;;AAMG;AACH;AAyBA;;;AAGG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type EmotionLabel = 'admiration' | 'amusement' | 'anger' | 'annoyance' | 'approval' | 'caring' | 'confusion' | 'curiosity' | 'desire' | 'disappointment' | 'disapproval' | 'disgust' | 'embarrassment' | 'excitement' | 'fear' | 'gratitude' | 'grief' | 'joy' | 'love' | 'nervousness' | 'neutral' | 'optimism' | 'pride' | 'realization' | 'relief' | 'remorse' | 'sadness' | 'surprise';
|
|
2
|
+
/** All 28 labels, in the SillyTavern canonical order. */
|
|
3
|
+
export declare const ALL_EMOTIONS: EmotionLabel[];
|
|
4
|
+
/**
|
|
5
|
+
* Classify a chat-message string into one of the 28 GoEmotions labels.
|
|
6
|
+
*
|
|
7
|
+
* Returns `'neutral'` when no rule fires, which is what every sprite pack
|
|
8
|
+
* uses as the fallback (and what `character_get_expression` falls back to
|
|
9
|
+
* server-side when the requested sprite is missing).
|
|
10
|
+
*
|
|
11
|
+
* @param text - The assistant's message text. Markdown formatting is fine —
|
|
12
|
+
* the regexes only care about word content.
|
|
13
|
+
* @param available - Optional restrict-set: only return labels present here.
|
|
14
|
+
* Useful when the caller knows which sprites the
|
|
15
|
+
* character actually ships and wants to avoid a Tauri
|
|
16
|
+
* round-trip for labels that will fall back anyway.
|
|
17
|
+
*/
|
|
18
|
+
export declare function classifyEmotion(text: string | null | undefined, available?: readonly string[]): EmotionLabel;
|
|
19
|
+
//# sourceMappingURL=emotionClassifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emotionClassifier.d.ts","sourceRoot":"","sources":["../../../../src/components/AIToolbar/utils/emotionClassifier.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,YAAY,GAClB,YAAY,GACZ,WAAW,GACX,OAAO,GACP,WAAW,GACX,UAAU,GACV,QAAQ,GACR,WAAW,GACX,WAAW,GACX,QAAQ,GACR,gBAAgB,GAChB,aAAa,GACb,SAAS,GACT,eAAe,GACf,YAAY,GACZ,MAAM,GACN,WAAW,GACX,OAAO,GACP,KAAK,GACL,MAAM,GACN,aAAa,GACb,SAAS,GACT,UAAU,GACV,OAAO,GACP,aAAa,GACb,QAAQ,GACR,SAAS,GACT,SAAS,GACT,UAAU,CAAC;AAEjB,yDAAyD;AACzD,eAAO,MAAM,YAAY,EAAE,YAAY,EA6BtC,CAAC;AAgNF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,CAuB5G"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Lightweight emotion classifier for assistant message text.
|
|
2
|
+
//
|
|
3
|
+
// Picks one of the 28 SillyTavern / GoEmotions labels so the AIToolbar can
|
|
4
|
+
// switch the assistant's avatar to the matching expression sprite (see
|
|
5
|
+
// `packages-extensions/seraphina-character-extension/characters/Seraphina/`
|
|
6
|
+
// for the canonical sprite layout: `neutral.png`, `joy.png`, `caring.png`,
|
|
7
|
+
// `surprise.png`, etc.).
|
|
8
|
+
//
|
|
9
|
+
// This is intentionally a heuristic (regex/keyword scoring) — fast, offline,
|
|
10
|
+
// no model dependency — and is the same shape (`text → label`) as a real
|
|
11
|
+
// GoEmotions classifier, so it can be transparently swapped for an ONNX
|
|
12
|
+
// transformer later without touching the call sites.
|
|
13
|
+
//
|
|
14
|
+
// Limitations:
|
|
15
|
+
// - English only; would need rework for i18n responses.
|
|
16
|
+
// - Misses subtle nuance (sarcasm, mixed emotions) — picks the *strongest*
|
|
17
|
+
// signal and never returns more than one label.
|
|
18
|
+
// - Stage directions in italics ("smiles warmly") count the same as inline
|
|
19
|
+
// dialogue; that's actually desirable for character-card style replies
|
|
20
|
+
// where mood lives in the prose.
|
|
21
|
+
/** All 28 labels, in the SillyTavern canonical order. */
|
|
22
|
+
const RULES = [{
|
|
23
|
+
label: 'joy',
|
|
24
|
+
patterns: [/\b(happy|happiness|joy(ful)?|delight(ed|ful)?|cheerful|glad)\b/gi, /\b(smile[sd]?|grin(s|ned|ning)?|beam(s|ing|ed)?)\b/gi, /:\)|=\)|<3+/g]
|
|
25
|
+
}, {
|
|
26
|
+
label: 'amusement',
|
|
27
|
+
patterns: [/\b(laugh(s|ed|ing|ter)?|chuckle[sd]?|giggle[sd]?|snicker(s|ed|ing)?)\b/gi, /\b(amus(ed|ing|ement)|funny|hilarious|teasing)\b/gi, /\bha+ha+\b/gi, /lol\b/gi]
|
|
28
|
+
}, {
|
|
29
|
+
label: 'love',
|
|
30
|
+
patterns: [/\b(i love you|love you|my love|beloved|darling|sweetheart|dearest)\b/gi, /\b(adore[sd]?|cherish(ed|es)?|smitten)\b/gi],
|
|
31
|
+
weight: 2
|
|
32
|
+
}, {
|
|
33
|
+
label: 'caring',
|
|
34
|
+
patterns: [/\b(gentle(ly)?|tender(ly)?|softly|kind(ly|ness)?|warm(ly|th)?|reassuring(ly)?)\b/gi, /\b(comfort(s|ed|ing)?|soothing(ly)?|protect(s|ing|ed)?|nurturing)\b/gi, /\b(are you (ok|okay|alright)|how are you feeling|don'?t worry)\b/gi]
|
|
35
|
+
}, {
|
|
36
|
+
label: 'admiration',
|
|
37
|
+
patterns: [/\b(impressive|impressed|brilliant|magnificent|incredible|amazing|remarkable|astonishing|stunning|breathtaking)\b/gi, /\b(well done|great job|so proud of you)\b/gi]
|
|
38
|
+
}, {
|
|
39
|
+
label: 'approval',
|
|
40
|
+
patterns: [/\b(approve|agree|exactly|precisely|that'?s right|good idea|sounds good|works for me)\b/gi, /\b(yes,?\s+(of course|absolutely|certainly))/gi]
|
|
41
|
+
}, {
|
|
42
|
+
label: 'disapproval',
|
|
43
|
+
patterns: [/\b(disapprove|that'?s wrong|i don'?t agree|i wouldn'?t|shouldn'?t have)\b/gi, /\b(unacceptable|not okay)\b/gi]
|
|
44
|
+
}, {
|
|
45
|
+
label: 'anger',
|
|
46
|
+
patterns: [/\b(angry|furious|enraged|seething|livid|outraged)\b/gi, /\b(scowl(s|ed|ing)?|glare[sd]?|snarl(s|ed|ing)?|growl(s|ed|ing)?)\b/gi, /\bhow dare you\b/gi],
|
|
47
|
+
weight: 2
|
|
48
|
+
}, {
|
|
49
|
+
label: 'annoyance',
|
|
50
|
+
patterns: [/\b(annoy(ed|ing|ance)?|irritat(ed|ing|ion)|frustrat(ed|ing|ion))\b/gi, /\b(sigh(s|ed|ing)?|huff(s|ed|ing)?|rolls? (her|his|their) eyes)\b/gi, /\b(ugh|tsk)\b/gi]
|
|
51
|
+
}, {
|
|
52
|
+
label: 'fear',
|
|
53
|
+
patterns: [/\b(afraid|scared|terrified|frightened|fearful|horrified)\b/gi, /\b(trembl(es|ed|ing)|shiver(s|ed|ing)?|flinch(es|ed|ing)?)\b/gi, /\b(panic(ked|king)?|dread)\b/gi],
|
|
54
|
+
weight: 2
|
|
55
|
+
}, {
|
|
56
|
+
label: 'nervousness',
|
|
57
|
+
patterns: [/\b(nervous(ly|ness)?|anxious(ly)?|uneasy|jittery|tense(ly)?|on edge)\b/gi, /\b(fidget(s|ed|ing)?|bites? (her|his|their) lip|wrings? (her|his|their) hands)\b/gi]
|
|
58
|
+
}, {
|
|
59
|
+
label: 'sadness',
|
|
60
|
+
patterns: [/\b(sad(ness|ly)?|unhappy|sorrow(ful)?|heartbroken|miserable|melancholy|forlorn)\b/gi, /\b(tear(s|ful|y)|crying|weep(s|ing|ed)?|sob(s|bing|bed)?)\b/gi, /:\(/g],
|
|
61
|
+
weight: 2
|
|
62
|
+
}, {
|
|
63
|
+
label: 'grief',
|
|
64
|
+
patterns: [/\b(grief|grieving|mourn(s|ed|ing)?|bereaved|devastated)\b/gi, /\b(loss of|passed away|gone forever)\b/gi],
|
|
65
|
+
weight: 2
|
|
66
|
+
}, {
|
|
67
|
+
label: 'remorse',
|
|
68
|
+
patterns: [/\b(i'?m sorry|i am sorry|my apologies|apologi[sz]e|forgive me|regret(s|ted|ting)?|guilty|guilt)\b/gi, /\b(shouldn'?t have|wish i hadn'?t)\b/gi],
|
|
69
|
+
weight: 2
|
|
70
|
+
}, {
|
|
71
|
+
label: 'disappointment',
|
|
72
|
+
patterns: [/\b(disappointed|disappointing|let down|underwhelm(ed|ing)?|expected (more|better))\b/gi]
|
|
73
|
+
}, {
|
|
74
|
+
label: 'embarrassment',
|
|
75
|
+
patterns: [/\b(embarrass(ed|ing|ment)?|flustered|mortified|sheepish(ly)?)\b/gi, /\b(blush(es|ed|ing)?|cheeks (turn|burn|flush))\b/gi]
|
|
76
|
+
}, {
|
|
77
|
+
label: 'disgust',
|
|
78
|
+
patterns: [/\b(disgust(ed|ing)?|revolted|repulsed|nauseat(ed|ing)|gross|yuck|ew)\b/gi, /\b(grimace[sd]?|wrinkles? (her|his|their) nose)\b/gi]
|
|
79
|
+
}, {
|
|
80
|
+
label: 'excitement',
|
|
81
|
+
patterns: [/\b(excited(ly)?|thrilled|exhilarat(ed|ing)|exhilaration|elated|ecstatic|stoked|pumped)\b/gi, /\b(can'?t wait|bouncing|jumps? up)\b/gi]
|
|
82
|
+
}, {
|
|
83
|
+
label: 'gratitude',
|
|
84
|
+
patterns: [/\b(thank you|thanks|thank(ful|fully)?|grateful(ly)?|appreciat(e|ed|ing|ion))\b/gi],
|
|
85
|
+
weight: 2
|
|
86
|
+
}, {
|
|
87
|
+
label: 'pride',
|
|
88
|
+
patterns: [/\b(proud(ly)?|pride)\b/gi, /\b(chin (held )?high|stands? tall)\b/gi]
|
|
89
|
+
}, {
|
|
90
|
+
label: 'relief',
|
|
91
|
+
patterns: [/\b(relief|relieved|reliev(es|ed|ing)?)\b/gi, /\b(exhale[sd]? (deeply|slowly)|breathes? out)\b/gi]
|
|
92
|
+
}, {
|
|
93
|
+
label: 'optimism',
|
|
94
|
+
patterns: [/\b(hopeful(ly)?|optimist(ic)?|things will (work|turn) out|look(ing)? forward|we'?ll figure)\b/gi]
|
|
95
|
+
}, {
|
|
96
|
+
label: 'desire',
|
|
97
|
+
patterns: [/\b(crave[sd]?|yearn(s|ed|ing)?|long(s|ed|ing) for|want(s|ed|ing)? you|need(s|ed|ing)? you)\b/gi, /\b(lean(s|ed|ing)? in close|breathless)\b/gi]
|
|
98
|
+
}, {
|
|
99
|
+
label: 'curiosity',
|
|
100
|
+
patterns: [/\b(curious(ly)?|curiosity|intrigu(ed|ing)|wonder(s|ed|ing)? (about|what|why|how))\b/gi, /\btell me more\b/gi]
|
|
101
|
+
}, {
|
|
102
|
+
label: 'confusion',
|
|
103
|
+
patterns: [/\b(confus(ed|ing|ion)|puzzl(ed|ing)|baffl(ed|ing)|perplex(ed|ing))\b/gi, /\b(tilts? (her|his|their) head|raises? an eyebrow|i don'?t understand|what do you mean)\b/gi, /\?\?+/g]
|
|
104
|
+
}, {
|
|
105
|
+
label: 'realization',
|
|
106
|
+
patterns: [/\b(realiz(es|ed|ing)|realisation|i see now|of course!|that makes sense|finally understand)\b/gi, /\b(aha|eureka)\b/gi]
|
|
107
|
+
}, {
|
|
108
|
+
label: 'surprise',
|
|
109
|
+
patterns: [/\b(surpris(ed|ing|e)|astonish(ed|ing)|astounded|shocked|stunned|taken aback)\b/gi, /\b(gasp(s|ed|ing)?|eyes (widen|go wide))\b/gi, /\b(oh!|wha[at]?\?!)/gi]
|
|
110
|
+
}];
|
|
111
|
+
/**
|
|
112
|
+
* Classify a chat-message string into one of the 28 GoEmotions labels.
|
|
113
|
+
*
|
|
114
|
+
* Returns `'neutral'` when no rule fires, which is what every sprite pack
|
|
115
|
+
* uses as the fallback (and what `character_get_expression` falls back to
|
|
116
|
+
* server-side when the requested sprite is missing).
|
|
117
|
+
*
|
|
118
|
+
* @param text - The assistant's message text. Markdown formatting is fine —
|
|
119
|
+
* the regexes only care about word content.
|
|
120
|
+
* @param available - Optional restrict-set: only return labels present here.
|
|
121
|
+
* Useful when the caller knows which sprites the
|
|
122
|
+
* character actually ships and wants to avoid a Tauri
|
|
123
|
+
* round-trip for labels that will fall back anyway.
|
|
124
|
+
*/
|
|
125
|
+
function classifyEmotion(text, available) {
|
|
126
|
+
if (!text) return 'neutral';
|
|
127
|
+
let bestLabel = 'neutral';
|
|
128
|
+
let bestScore = 0;
|
|
129
|
+
for (const rule of RULES) {
|
|
130
|
+
const weight = rule.weight ?? 1;
|
|
131
|
+
let score = 0;
|
|
132
|
+
for (const pattern of rule.patterns) {
|
|
133
|
+
const matches = text.match(pattern);
|
|
134
|
+
if (matches) score += matches.length * weight;
|
|
135
|
+
}
|
|
136
|
+
if (score > bestScore) {
|
|
137
|
+
bestScore = score;
|
|
138
|
+
bestLabel = rule.label;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return bestLabel;
|
|
142
|
+
}export{classifyEmotion};//# sourceMappingURL=emotionClassifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emotionClassifier.js","sources":["../../../../src/components/AIToolbar/utils/emotionClassifier.ts"],"sourcesContent":[null],"names":[],"mappings":"AAqBA;AA8BA;AACA;AA6OA;;;;;;;;;;;;;AAaG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persisted preference for which installed character card is **active**
|
|
3
|
+
* across the toolbar + dashboard webviews (`character_list[].file_name` stem —
|
|
4
|
+
* e.g. `"Aria"`, `"Seraphina"`).
|
|
5
|
+
*
|
|
6
|
+
* Mirrors the `useChatBackground` pattern: localStorage + `storage` events +
|
|
7
|
+
* Tauri `emit`/`listen` so the dashboard sees the selection without sharing a
|
|
8
|
+
* `window` reference with the floating bar.
|
|
9
|
+
*/
|
|
10
|
+
/** localStorage key — exported for `storage` listeners in other hooks. */
|
|
11
|
+
export declare const ACTIVE_CHARACTER_FILE_NAME_STORAGE_KEY = "yantra:active-character:file-name";
|
|
12
|
+
/** Event name broadcast when the preferred character changes (payload: `{ fileName: string | null }`). */
|
|
13
|
+
export declare const ACTIVE_CHARACTER_CHANGE_EVENT = "yantra:active-character-change";
|
|
14
|
+
export declare function readPreferredActiveCharacterFileName(): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Write the user's character choice and fan out so every webview recomputes
|
|
17
|
+
* active character (toolbar + `/chat`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function setPreferredActiveCharacterFileName(fileName: string | null): Promise<void>;
|
|
20
|
+
/** Pick the character row that matches the stored preference; otherwise list[0]. */
|
|
21
|
+
export declare function resolveActiveCharacterFromList<T extends {
|
|
22
|
+
file_name?: string | null;
|
|
23
|
+
}>(list: T[] | null | undefined): T | null;
|
|
24
|
+
//# sourceMappingURL=activeCharacterPreference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activeCharacterPreference.d.ts","sourceRoot":"","sources":["../../src/hooks/activeCharacterPreference.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,0EAA0E;AAC1E,eAAO,MAAM,sCAAsC,sCAAsC,CAAC;AAE1F,0GAA0G;AAC1G,eAAO,MAAM,6BAA6B,mCAAmC,CAAC;AAE9E,wBAAgB,oCAAoC,IAAI,MAAM,GAAG,IAAI,CAOpE;AAYD;;;GAGG;AACH,wBAAsB,mCAAmC,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBhG;AAED,oFAAoF;AACpF,wBAAgB,8BAA8B,CAAC,CAAC,SAAS;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAClF,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,GAAG,SAAS,GAC7B,CAAC,GAAG,IAAI,CAQV"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persisted preference for which installed character card is **active**
|
|
3
|
+
* across the toolbar + dashboard webviews (`character_list[].file_name` stem —
|
|
4
|
+
* e.g. `"Aria"`, `"Seraphina"`).
|
|
5
|
+
*
|
|
6
|
+
* Mirrors the `useChatBackground` pattern: localStorage + `storage` events +
|
|
7
|
+
* Tauri `emit`/`listen` so the dashboard sees the selection without sharing a
|
|
8
|
+
* `window` reference with the floating bar.
|
|
9
|
+
*/
|
|
10
|
+
/** localStorage key — exported for `storage` listeners in other hooks. */
|
|
11
|
+
const ACTIVE_CHARACTER_FILE_NAME_STORAGE_KEY = 'yantra:active-character:file-name';
|
|
12
|
+
/** Event name broadcast when the preferred character changes (payload: `{ fileName: string | null }`). */
|
|
13
|
+
const ACTIVE_CHARACTER_CHANGE_EVENT = 'yantra:active-character-change';
|
|
14
|
+
function readPreferredActiveCharacterFileName() {
|
|
15
|
+
if (typeof window === 'undefined') return null;
|
|
16
|
+
try {
|
|
17
|
+
return window.localStorage.getItem(ACTIVE_CHARACTER_FILE_NAME_STORAGE_KEY);
|
|
18
|
+
} catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function safeEmit(event, payload) {
|
|
23
|
+
try {
|
|
24
|
+
// @ts-ignore optional dynamic import
|
|
25
|
+
const mod = await import('@tauri-apps/api/event');
|
|
26
|
+
await mod.emit(event, payload);
|
|
27
|
+
} catch {
|
|
28
|
+
/* non-Tauri or event module missing */
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Write the user's character choice and fan out so every webview recomputes
|
|
33
|
+
* active character (toolbar + `/chat`).
|
|
34
|
+
*/
|
|
35
|
+
async function setPreferredActiveCharacterFileName(fileName) {
|
|
36
|
+
if (typeof window === 'undefined') return;
|
|
37
|
+
try {
|
|
38
|
+
if (fileName && fileName.trim()) {
|
|
39
|
+
window.localStorage.setItem(ACTIVE_CHARACTER_FILE_NAME_STORAGE_KEY, fileName.trim());
|
|
40
|
+
} else {
|
|
41
|
+
window.localStorage.removeItem(ACTIVE_CHARACTER_FILE_NAME_STORAGE_KEY);
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
// ignore quota
|
|
45
|
+
}
|
|
46
|
+
window.dispatchEvent(new CustomEvent(ACTIVE_CHARACTER_CHANGE_EVENT, {
|
|
47
|
+
detail: {
|
|
48
|
+
fileName: fileName?.trim() || null
|
|
49
|
+
}
|
|
50
|
+
}));
|
|
51
|
+
await safeEmit(ACTIVE_CHARACTER_CHANGE_EVENT, {
|
|
52
|
+
fileName: fileName?.trim() || null
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/** Pick the character row that matches the stored preference; otherwise list[0]. */
|
|
56
|
+
function resolveActiveCharacterFromList(list) {
|
|
57
|
+
if (!list?.length) return null;
|
|
58
|
+
const pref = readPreferredActiveCharacterFileName();
|
|
59
|
+
if (pref) {
|
|
60
|
+
const match = list.find(c => c.file_name === pref);
|
|
61
|
+
if (match) return match;
|
|
62
|
+
}
|
|
63
|
+
return list[0] ?? null;
|
|
64
|
+
}export{ACTIVE_CHARACTER_CHANGE_EVENT,ACTIVE_CHARACTER_FILE_NAME_STORAGE_KEY,readPreferredActiveCharacterFileName,resolveActiveCharacterFromList,setPreferredActiveCharacterFileName};//# sourceMappingURL=activeCharacterPreference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activeCharacterPreference.js","sources":["../../src/hooks/activeCharacterPreference.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;;;;AAQG;AAEH;AACA,MAAA,sCAAa,GAAA;AAEb;AACA,MAAA,6BAAa,GAAA;AAEb,SAAA,oCAAgB,GAAA;AAmBhB,EAAA,IAAA,OAAA,MAAA,KAAA,WAAA,EAAA,OAAA,IAAA;;;AAGG,EAAA,CAAA,CAAA,MAAA;AACH,IAAA,OAAA,IAAA;AAqBA,EAAA;AACA;AAA2D,eAAU,QAAQ,CAAA,KAAO,EAAA,OAAA,EAAA;AAAE,EAAA,IAClF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/lib/hooks/index.d.ts
CHANGED
package/lib/hooks/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{default as PageLoading}from'./components/PageLoading/index.js';export{ApplicationErrorHandler}from'./components/ErrorHandlers/ApplicationErrorHandler.js';export{ErrorBoundary}from'./components/ErrorHandlers/ErrorBoundary.js';export{LayoutErrorBoundary}from'./components/ErrorHandlers/LayoutErrorBoundary.js';export{RemixErrorBoundary}from'./components/ErrorHandlers/RemixErrorBoundary.js';export{SPAErrorBoundary}from'./components/ErrorHandlers/SPAErrorBoundary.js';export{ReactTable}from'./components/ReactTable/Table.js';export{DefaultColumnFilter,SelectColumnFilter}from'./components/ReactTable/TableFilters.js';export{Error404}from'./components/ErrorPages/404.js';export{Error500}from'./components/ErrorPages/500.js';export{Error403}from'./components/ErrorPages/403.js';export{PageContainer}from'./components/PageContainer/PageContainer.js';export{Spin}from'./components/Spin/index.js';export{OTPInput}from'./components/OTP/OTPInput.js';export{SingleInput}from'./components/OTP/SingleInput.js';export{useOTPInput}from'./components/OTP/hooks.js';export{OTPVerification}from'./components/OTP/OTPVerification.js';export{SearchInput}from'./components/Search/SearchInput.js';export{Select,SelectContent,SelectItem,SelectSearch,SelectTrigger,SelectValue}from'./components/Select/Select.js';export{DatePicker}from'./components/DatePicker/DatePicker.js';export{Dialog}from'./components/Dialog/Dialog.js';export{TailwindUiButton}from'./components/Button/Button.js';export{TailwindThemeProvider,ThemeContext,themes}from'./components/ThemeProvider/ThemeProvider.js';export{ThemeToggle}from'./components/ThemeProvider/ThemeToggle.js';export{LanguageMenuDropdown}from'./components/LanguageMenuDropdown/LanguageMenuDropdown.js';export{InputToolBar}from'./components/InputToolBar/InputToolBar.js';export{getDefaultLeftItems,getDefaultRightItems}from'./components/InputToolBar/defaults.js';export{AIToolbar,AIToolbarInputSurface,AIToolbarLeading,AIToolbarMain,AIToolbarStatusDot,AIToolbarTrailing}from'./components/AIToolbar/components/AIToolbarPrimitives.js';export{Completion}from'./components/AIToolbar/components/completion/index.js';export{SystemAudio}from'./components/AIToolbar/components/speech/index.js';export{AudioVisualizer}from'./components/AIToolbar/components/speech/audio-visualizer.js';export{StatusIndicator}from'./components/AIToolbar/components/speech/StatusIndicator.js';export{AIToolBar}from'./components/AIToolbar/components/AIToolBar.js';export{CustomCursor}from'./components/AIToolbar/components/CustomCursor.js';export{MessageHistory}from'./components/AIToolbar/components/completion/MessageHistory.js';export{Screenshot}from'./components/AIToolbar/components/completion/Screenshot.js';export{Header}from'./components/AIToolbar/components/speech/Header.js';export{ModeSwitcher}from'./components/AIToolbar/components/speech/ModeSwitcher.js';export{PermissionFlow}from'./components/AIToolbar/components/speech/PermissionFlow.js';export{YantraIcon}from'./components/YantraIcon.js';export{Markdown as AIToolbarMarkdown}from'./components/AIToolbar/components/Markdown/index.js';export{MarkdownBreadcrumbs}from'./components/Markdown/MarkdownBreadcrumbs.js';export{MarkdownCopyButton}from'./components/Markdown/MarkdownCopyButton.js';export{MarkdownHeader}from'./components/Markdown/MarkdownHeader.js';export{MarkdownNavigation}from'./components/Markdown/MarkdownNavigation.js';export{MarkdownPage}from'./components/Markdown/MarkdownPage.js';export{MarkdownTableOfContents}from'./components/Markdown/MarkdownTableOfContents.js';export{useTheme}from'./hooks/useTheme.js';export{useWindowSize}from'./hooks/useWindowSize.js';export{ToastContainer,useToast,useToastCloseAll}from'./hooks/useToast.js';export{useMediaQuery}from'./hooks/useMediaQuery.js';export{cn}from'./utils/util.js';export{AssistantMessageActions}from'./components/AIToolbar/components/completion/AssistantMessageActions.js';export{DragButton}from'./components/AIToolbar/components/DragButton.js';//# sourceMappingURL=index.js.map
|
|
1
|
+
export{default as PageLoading}from'./components/PageLoading/index.js';export{ApplicationErrorHandler}from'./components/ErrorHandlers/ApplicationErrorHandler.js';export{ErrorBoundary}from'./components/ErrorHandlers/ErrorBoundary.js';export{LayoutErrorBoundary}from'./components/ErrorHandlers/LayoutErrorBoundary.js';export{RemixErrorBoundary}from'./components/ErrorHandlers/RemixErrorBoundary.js';export{SPAErrorBoundary}from'./components/ErrorHandlers/SPAErrorBoundary.js';export{ReactTable}from'./components/ReactTable/Table.js';export{DefaultColumnFilter,SelectColumnFilter}from'./components/ReactTable/TableFilters.js';export{Error404}from'./components/ErrorPages/404.js';export{Error500}from'./components/ErrorPages/500.js';export{Error403}from'./components/ErrorPages/403.js';export{PageContainer}from'./components/PageContainer/PageContainer.js';export{Spin}from'./components/Spin/index.js';export{OTPInput}from'./components/OTP/OTPInput.js';export{SingleInput}from'./components/OTP/SingleInput.js';export{useOTPInput}from'./components/OTP/hooks.js';export{OTPVerification}from'./components/OTP/OTPVerification.js';export{SearchInput}from'./components/Search/SearchInput.js';export{Select,SelectContent,SelectItem,SelectSearch,SelectTrigger,SelectValue}from'./components/Select/Select.js';export{DatePicker}from'./components/DatePicker/DatePicker.js';export{Dialog}from'./components/Dialog/Dialog.js';export{TailwindUiButton}from'./components/Button/Button.js';export{TailwindThemeProvider,ThemeContext,themes}from'./components/ThemeProvider/ThemeProvider.js';export{ThemeToggle}from'./components/ThemeProvider/ThemeToggle.js';export{LanguageMenuDropdown}from'./components/LanguageMenuDropdown/LanguageMenuDropdown.js';export{InputToolBar}from'./components/InputToolBar/InputToolBar.js';export{getDefaultLeftItems,getDefaultRightItems}from'./components/InputToolBar/defaults.js';export{AIToolbar,AIToolbarInputSurface,AIToolbarLeading,AIToolbarMain,AIToolbarStatusDot,AIToolbarTrailing}from'./components/AIToolbar/components/AIToolbarPrimitives.js';export{Completion}from'./components/AIToolbar/components/completion/index.js';export{SystemAudio}from'./components/AIToolbar/components/speech/index.js';export{AudioVisualizer}from'./components/AIToolbar/components/speech/audio-visualizer.js';export{StatusIndicator}from'./components/AIToolbar/components/speech/StatusIndicator.js';export{AIToolBar}from'./components/AIToolbar/components/AIToolBar.js';export{CustomCursor}from'./components/AIToolbar/components/CustomCursor.js';export{MessageHistory}from'./components/AIToolbar/components/completion/MessageHistory.js';export{Screenshot}from'./components/AIToolbar/components/completion/Screenshot.js';export{Header}from'./components/AIToolbar/components/speech/Header.js';export{ModeSwitcher}from'./components/AIToolbar/components/speech/ModeSwitcher.js';export{PermissionFlow}from'./components/AIToolbar/components/speech/PermissionFlow.js';export{YantraIcon}from'./components/YantraIcon.js';export{Markdown as AIToolbarMarkdown}from'./components/AIToolbar/components/Markdown/index.js';export{MarkdownBreadcrumbs}from'./components/Markdown/MarkdownBreadcrumbs.js';export{MarkdownCopyButton}from'./components/Markdown/MarkdownCopyButton.js';export{MarkdownHeader}from'./components/Markdown/MarkdownHeader.js';export{MarkdownNavigation}from'./components/Markdown/MarkdownNavigation.js';export{MarkdownPage}from'./components/Markdown/MarkdownPage.js';export{MarkdownTableOfContents}from'./components/Markdown/MarkdownTableOfContents.js';export{ACTIVE_CHARACTER_CHANGE_EVENT,ACTIVE_CHARACTER_FILE_NAME_STORAGE_KEY,readPreferredActiveCharacterFileName,resolveActiveCharacterFromList,setPreferredActiveCharacterFileName}from'./hooks/activeCharacterPreference.js';export{useTheme}from'./hooks/useTheme.js';export{useWindowSize}from'./hooks/useWindowSize.js';export{ToastContainer,useToast,useToastCloseAll}from'./hooks/useToast.js';export{useMediaQuery}from'./hooks/useMediaQuery.js';export{cn}from'./utils/util.js';export{AssistantMessageActions}from'./components/AIToolbar/components/completion/AssistantMessageActions.js';export{DragButton}from'./components/AIToolbar/components/DragButton.js';//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@admin-layout/tailwind-ui",
|
|
3
|
-
"version": "12.2.4-alpha.
|
|
3
|
+
"version": "12.2.4-alpha.59",
|
|
4
4
|
"description": "Sample core for higher packages to depend on",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "CDMBase LLC",
|
|
@@ -96,5 +96,5 @@
|
|
|
96
96
|
"typescript": {
|
|
97
97
|
"definition": "lib/index.d.ts"
|
|
98
98
|
},
|
|
99
|
-
"gitHead": "
|
|
99
|
+
"gitHead": "628dab51faaae1c1ab545c071a2252395659fe7e"
|
|
100
100
|
}
|