@lastbrain/ai-ui-react 1.0.74 → 1.0.75
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/components/AiChipLabel.d.ts.map +1 -1
- package/dist/components/AiContextButton.d.ts.map +1 -1
- package/dist/components/AiContextButton.js +3 -2
- package/dist/components/AiImageButton.d.ts.map +1 -1
- package/dist/components/AiImageButton.js +4 -1
- package/dist/components/AiModelSelect.d.ts.map +1 -1
- package/dist/components/AiStatusButton.d.ts.map +1 -1
- package/dist/components/LBConnectButton.d.ts.map +1 -1
- package/dist/components/LBConnectButton.js +1 -3
- package/dist/components/LBSigninModal.d.ts.map +1 -1
- package/dist/context/I18nContext.d.ts +1 -1
- package/dist/context/I18nContext.d.ts.map +1 -1
- package/dist/context/I18nContext.js +1 -1
- package/dist/hooks/useLoadingTimer.d.ts.map +1 -1
- package/dist/hooks/useLoadingTimer.js +11 -7
- package/package.json +1 -1
- package/src/components/AiChipLabel.tsx +1 -4
- package/src/components/AiContextButton.tsx +14 -5
- package/src/components/AiImageButton.tsx +8 -2
- package/src/components/AiModelSelect.tsx +3 -1
- package/src/components/AiPromptPanel.tsx +52 -43
- package/src/components/AiStatusButton.tsx +37 -19
- package/src/components/LBApiKeySelector.tsx +5 -5
- package/src/components/LBConnectButton.tsx +1 -3
- package/src/components/LBSigninModal.tsx +10 -8
- package/src/context/I18nContext.tsx +6 -2
- package/src/hooks/useLoadingTimer.ts +14 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiChipLabel.d.ts","sourceRoot":"","sources":["../../src/components/AiChipLabel.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAA0C,MAAM,OAAO,CAAC;AAS/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGjD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,OAAmB,EACnB,IAAW,EACX,MAAe,EACf,SAAS,EACT,KAAK,EAAE,WAAW,GACnB,EAAE,gBAAgB,2CAiBlB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAU,EACV,QAAQ,EACR,WAAW,EACX,OAAO,EACP,QAAQ,EACR,eAAuB,EACvB,SAAS,EACT,YAAY,EACZ,aAAa,EACb,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,IAAW,EACX,MAAe,GAChB,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"AiChipLabel.d.ts","sourceRoot":"","sources":["../../src/components/AiChipLabel.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAA0C,MAAM,OAAO,CAAC;AAS/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGjD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,OAAmB,EACnB,IAAW,EACX,MAAe,EACf,SAAS,EACT,KAAK,EAAE,WAAW,GACnB,EAAE,gBAAgB,2CAiBlB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAU,EACV,QAAQ,EACR,WAAW,EACX,OAAO,EACP,QAAQ,EACR,eAAuB,EACvB,SAAS,EACT,YAAY,EACZ,aAAa,EACb,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,IAAW,EACX,MAAe,GAChB,EAAE,gBAAgB,2CA0MlB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiContextButton.d.ts","sourceRoot":"","sources":["../../src/components/AiContextButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,KAAK,WAAW,GACZ,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,OAAO,EAAE,GACT;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAE/B,MAAM,WAAW,oBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,WAAW,EAAE,WAAW,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,OAAO,EAAE,QAAQ,EACjB,GAAG,WAAW,EACf,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"AiContextButton.d.ts","sourceRoot":"","sources":["../../src/components/AiContextButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,KAAK,WAAW,GACZ,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,OAAO,EAAE,GACT;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAE/B,MAAM,WAAW,oBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,WAAW,EAAE,WAAW,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,OAAO,EAAE,QAAQ,EACjB,GAAG,WAAW,EACf,EAAE,oBAAoB,2CA6StB"}
|
|
@@ -142,12 +142,13 @@ export function AiContextButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId,
|
|
|
142
142
|
const variantClass = variant === "light" ? "ai-btn--light" : "";
|
|
143
143
|
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "relative inline-block ai-glow", children: [_jsx("button", { ...buttonProps, onClick: handleOpenPanel, disabled: disabled || loading || !isAuthReady, className: `ai-btn ai-context-btn ${variantClass} ${sizeClass} ${radiusClass} ${className || ""}`, title: !isAuthReady
|
|
144
144
|
? t("auth.required", "Authentication required")
|
|
145
|
-
: t("ai.analyze", "Analyze with AI"), children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), _jsx("span", { children: t("ai.analyzing", "Analyzing...") })] })) : !isAuthReady ? (_jsxs(_Fragment, { children: [_jsx(Lock, { size: 16 }), children || (_jsx("span", { children: t("auth.connectRequired", "Connection required") }))] })) : (_jsxs(_Fragment, { children: [_jsx(Sparkles, { size: 16 }), children || _jsx("span", { children: t("ai.context.buttonAnalyze", "Analyze") })] })) }), isOpen ? (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: () => setIsOpen(false), onSubmit: handleSubmit, uiMode: uiMode, models: [], enableModelManagement: true, modelCategory: "text", baseUrl: baseUrl, apiKey: apiKeyId })) : null] }), isResultOpen && analysisResult ? (_jsx("div", { className: "ai-signin-overlay ai-overlay-panel", onClick: (e) => {
|
|
145
|
+
: t("ai.analyze", "Analyze with AI"), children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), _jsx("span", { children: t("ai.analyzing", "Analyzing...") })] })) : !isAuthReady ? (_jsxs(_Fragment, { children: [_jsx(Lock, { size: 16 }), children || (_jsx("span", { children: t("auth.connectRequired", "Connection required") }))] })) : (_jsxs(_Fragment, { children: [_jsx(Sparkles, { size: 16 }), children || (_jsx("span", { children: t("ai.context.buttonAnalyze", "Analyze") }))] })) }), isOpen ? (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: () => setIsOpen(false), onSubmit: handleSubmit, uiMode: uiMode, models: [], enableModelManagement: true, modelCategory: "text", baseUrl: baseUrl, apiKey: apiKeyId })) : null] }), isResultOpen && analysisResult ? (_jsx("div", { className: "ai-signin-overlay ai-overlay-panel", onClick: (e) => {
|
|
146
146
|
if (e.target === e.currentTarget) {
|
|
147
147
|
setIsResultOpen(false);
|
|
148
148
|
setAnalysisResult(null);
|
|
149
149
|
}
|
|
150
|
-
}, children: _jsxs("div", { className: "ai-popover ai-result-modal", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "ai-result-header", children: [_jsxs("div", { className: "ai-row", children: [_jsx(FileText, { size: 18 }), _jsx("h2", { className: "ai-result-title", children: resultModalTitle ||
|
|
150
|
+
}, children: _jsxs("div", { className: "ai-popover ai-result-modal", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "ai-result-header", children: [_jsxs("div", { className: "ai-row", children: [_jsx(FileText, { size: 18 }), _jsx("h2", { className: "ai-result-title", children: resultModalTitle ||
|
|
151
|
+
t("ai.context.resultTitle", "Analysis result") })] }), _jsxs("div", { className: "ai-row", children: [_jsxs("button", { type: "button", className: `ai-btn ai-btn--ghost ai-btn--compact ${sizeClass} ${radiusClass}`, onClick: saveToFile, children: [_jsx(Download, { size: 14 }), t("common.save", "Save")] }), _jsx("button", { type: "button", className: "ai-icon-btn", onClick: () => {
|
|
151
152
|
setIsResultOpen(false);
|
|
152
153
|
setAnalysisResult(null);
|
|
153
154
|
}, "aria-label": t("common.closeLabel", "Close"), children: _jsx(X, { size: 16 }) })] })] }), _jsxs("div", { className: "ai-result-body", children: [_jsxs("div", { className: "ai-result-block", children: [_jsx("h3", { className: "ai-result-subtitle", children: t("common.promptUsed", "Prompt used") }), _jsx("pre", { className: "ai-result-code", children: analysisResult.prompt })] }), _jsxs("div", { className: "ai-result-block", children: [_jsx("h3", { className: "ai-result-subtitle", children: t("common.result", "Result") }), _jsx("div", { className: "ai-result-content", children: analysisResult.content })] }), _jsxs("div", { className: "ai-result-meta ai-between", children: [_jsxs("span", { children: [t("ai.context.cost", "Cost"), ": $", (apiKeyId?.includes("dev")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiImageButton.d.ts","sourceRoot":"","sources":["../../src/components/AiImageButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAS5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,MAAM,WAAW,kBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,OAAO,CAAC,EAAE,CACR,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,aAAoB,EACpB,WAAW,EACX,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,GAAG,WAAW,EACf,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"AiImageButton.d.ts","sourceRoot":"","sources":["../../src/components/AiImageButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAS5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,MAAM,WAAW,kBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,OAAO,CAAC,EAAE,CACR,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,aAAoB,EACpB,WAAW,EACX,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,GAAG,WAAW,EACf,EAAE,kBAAkB,2CAoRpB"}
|
|
@@ -61,7 +61,10 @@ export function AiImageButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, ui
|
|
|
61
61
|
return;
|
|
62
62
|
try {
|
|
63
63
|
await onImageSave(generatedImage.url);
|
|
64
|
-
onToast?.({
|
|
64
|
+
onToast?.({
|
|
65
|
+
type: "success",
|
|
66
|
+
message: t("ai.image.savedSuccess", "Image saved"),
|
|
67
|
+
});
|
|
65
68
|
}
|
|
66
69
|
catch (_error) {
|
|
67
70
|
onToast?.({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiModelSelect.d.ts","sourceRoot":"","sources":["../../src/components/AiModelSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"AiModelSelect.d.ts","sourceRoot":"","sources":["../../src/components/AiModelSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,EAAE,kBAAkB,2CAoBpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAU,MAAM,uBAAuB,CAAC;AAuB9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGjD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAmHD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAe,EACf,SAAc,EACd,IAAW,EACX,MAAe,GAChB,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAU,MAAM,uBAAuB,CAAC;AAuB9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGjD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAmHD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAe,EACf,SAAc,EACd,IAAW,EACX,MAAe,GAChB,EAAE,mBAAmB,2CA2iBrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LBConnectButton.d.ts","sourceRoot":"","sources":["../../src/components/LBConnectButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAO5B,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,SAAc,EACd,WAAW,EACX,WAAW,GACZ,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"LBConnectButton.d.ts","sourceRoot":"","sources":["../../src/components/LBConnectButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAO5B,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,SAAc,EACd,WAAW,EACX,WAAW,GACZ,EAAE,oBAAoB,2CAuDtB;AAED;;;GAGG;AACH,UAAU,gBAAgB;IACxB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAExD"}
|
|
@@ -25,9 +25,7 @@ export function LBConnectButton({ label, className = "", onConnected, onOpenModa
|
|
|
25
25
|
onOpenModal?.();
|
|
26
26
|
};
|
|
27
27
|
const connectLabel = label || t("auth.signIn", "Sign in");
|
|
28
|
-
const buttonLabel = status === "ready" && user
|
|
29
|
-
? t("auth.signOut", "Sign out")
|
|
30
|
-
: connectLabel;
|
|
28
|
+
const buttonLabel = status === "ready" && user ? t("auth.signOut", "Sign out") : connectLabel;
|
|
31
29
|
return (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: handleClick, className: className || "ai-btn ai-btn--auth", disabled: status === "loading", children: status === "loading" ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "animate-spin" }), t("common.loading", "Loading...")] })) : status === "ready" && user ? (_jsxs(_Fragment, { children: [_jsx(LogOut, { size: 16 }), buttonLabel] })) : (_jsxs(_Fragment, { children: [_jsx(LogIn, { size: 16 }), buttonLabel] })) }), _jsx(LBSigninModal, { isOpen: showModal, onClose: () => setShowModal(false) })] }));
|
|
32
30
|
}
|
|
33
31
|
export function LBAuthModal({ onClose }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LBSigninModal.d.ts","sourceRoot":"","sources":["../../src/components/LBSigninModal.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAQ5B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"LBSigninModal.d.ts","sourceRoot":"","sources":["../../src/components/LBSigninModal.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAQ5B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,kBAAkB,sCAsPpE"}
|
|
@@ -9,7 +9,7 @@ export interface I18nProviderProps {
|
|
|
9
9
|
children: ReactNode;
|
|
10
10
|
lang?: LBSupportedLang;
|
|
11
11
|
}
|
|
12
|
-
export declare function I18nProvider({ children, lang }: I18nProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function I18nProvider({ children, lang, }: I18nProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
13
13
|
export declare function useI18n(): I18nContextValue;
|
|
14
14
|
export {};
|
|
15
15
|
//# sourceMappingURL=I18nContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"I18nContext.d.ts","sourceRoot":"","sources":["../../src/context/I18nContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAQ3E,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAatE,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEvD,UAAU,gBAAgB;IACxB,IAAI,EAAE,eAAe,CAAC;IACtB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,KAAK,MAAM,CAAC;CACzE;AAeD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED,wBAAgB,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"I18nContext.d.ts","sourceRoot":"","sources":["../../src/context/I18nContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAQ3E,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAatE,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEvD,UAAU,gBAAgB;IACxB,IAAI,EAAE,eAAe,CAAC;IACtB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,KAAK,MAAM,CAAC;CACzE;AAeD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,IAAkB,GACnB,EAAE,iBAAiB,2CAmBnB;AAED,wBAAgB,OAAO,qBAEtB"}
|
|
@@ -25,7 +25,7 @@ const I18nContext = createContext({
|
|
|
25
25
|
return template.replace(/\{(\w+)\}/g, (_, p) => params[p] !== undefined ? String(params[p]) : `{${p}}`);
|
|
26
26
|
},
|
|
27
27
|
});
|
|
28
|
-
export function I18nProvider({ children, lang = defaultLang }) {
|
|
28
|
+
export function I18nProvider({ children, lang = defaultLang, }) {
|
|
29
29
|
const safeLang = dictionaries[lang] ? lang : defaultLang;
|
|
30
30
|
const value = useMemo(() => {
|
|
31
31
|
const dict = dictionaries[safeLang] || dictionaries[defaultLang];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLoadingTimer.d.ts","sourceRoot":"","sources":["../../src/hooks/useLoadingTimer.ts"],"names":[],"mappings":"AAWA,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO;;;
|
|
1
|
+
{"version":3,"file":"useLoadingTimer.d.ts","sourceRoot":"","sources":["../../src/hooks/useLoadingTimer.ts"],"names":[],"mappings":"AAWA,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO;;;EA0B9C"}
|
|
@@ -11,17 +11,21 @@ export function useLoadingTimer(active) {
|
|
|
11
11
|
const [seconds, setSeconds] = useState(0);
|
|
12
12
|
useEffect(() => {
|
|
13
13
|
if (!active) {
|
|
14
|
-
setSeconds(0);
|
|
15
|
-
return;
|
|
14
|
+
const timeoutId = window.setTimeout(() => setSeconds(0), 0);
|
|
15
|
+
return () => window.clearTimeout(timeoutId);
|
|
16
16
|
}
|
|
17
|
-
setSeconds(0);
|
|
18
|
-
const
|
|
17
|
+
const resetId = window.setTimeout(() => setSeconds(0), 0);
|
|
18
|
+
const intervalId = window.setInterval(() => {
|
|
19
19
|
setSeconds((prev) => prev + 1);
|
|
20
20
|
}, 1000);
|
|
21
|
-
return () =>
|
|
21
|
+
return () => {
|
|
22
|
+
window.clearTimeout(resetId);
|
|
23
|
+
window.clearInterval(intervalId);
|
|
24
|
+
};
|
|
22
25
|
}, [active]);
|
|
26
|
+
const displaySeconds = active ? seconds : 0;
|
|
23
27
|
return {
|
|
24
|
-
seconds,
|
|
25
|
-
formatted: formatElapsed(
|
|
28
|
+
seconds: displaySeconds,
|
|
29
|
+
formatted: formatElapsed(displaySeconds),
|
|
26
30
|
};
|
|
27
31
|
}
|
package/package.json
CHANGED
|
@@ -212,10 +212,7 @@ Exemple de réponse attendue: javascript, react, frontend, api, development`;
|
|
|
212
212
|
onKeyDown={handleKeyDown}
|
|
213
213
|
placeholder={
|
|
214
214
|
placeholder ||
|
|
215
|
-
t(
|
|
216
|
-
"ai.chips.placeholder",
|
|
217
|
-
"Type and press Enter to add tags..."
|
|
218
|
-
)
|
|
215
|
+
t("ai.chips.placeholder", "Type and press Enter to add tags...")
|
|
219
216
|
}
|
|
220
217
|
className={`ai-control ai-control-input ai-control-input--with-action ${sizeClass} ${radiusClass}`}
|
|
221
218
|
/>
|
|
@@ -208,7 +208,9 @@ export function AiContextButton({
|
|
|
208
208
|
)
|
|
209
209
|
? 0
|
|
210
210
|
: analysisResult.cost
|
|
211
|
-
).toFixed(
|
|
211
|
+
).toFixed(
|
|
212
|
+
6
|
|
213
|
+
)}\n${t("ai.context.requestId", "Request ID")}: ${analysisResult.requestId || "N/A"}`;
|
|
212
214
|
|
|
213
215
|
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
|
|
214
216
|
const url = URL.createObjectURL(blob);
|
|
@@ -254,7 +256,9 @@ export function AiContextButton({
|
|
|
254
256
|
) : (
|
|
255
257
|
<>
|
|
256
258
|
<Sparkles size={16} />
|
|
257
|
-
{children ||
|
|
259
|
+
{children || (
|
|
260
|
+
<span>{t("ai.context.buttonAnalyze", "Analyze")}</span>
|
|
261
|
+
)}
|
|
258
262
|
</>
|
|
259
263
|
)}
|
|
260
264
|
</button>
|
|
@@ -292,7 +296,8 @@ export function AiContextButton({
|
|
|
292
296
|
<div className="ai-row">
|
|
293
297
|
<FileText size={18} />
|
|
294
298
|
<h2 className="ai-result-title">
|
|
295
|
-
{resultModalTitle ||
|
|
299
|
+
{resultModalTitle ||
|
|
300
|
+
t("ai.context.resultTitle", "Analysis result")}
|
|
296
301
|
</h2>
|
|
297
302
|
</div>
|
|
298
303
|
<div className="ai-row">
|
|
@@ -320,12 +325,16 @@ export function AiContextButton({
|
|
|
320
325
|
|
|
321
326
|
<div className="ai-result-body">
|
|
322
327
|
<div className="ai-result-block">
|
|
323
|
-
<h3 className="ai-result-subtitle">
|
|
328
|
+
<h3 className="ai-result-subtitle">
|
|
329
|
+
{t("common.promptUsed", "Prompt used")}
|
|
330
|
+
</h3>
|
|
324
331
|
<pre className="ai-result-code">{analysisResult.prompt}</pre>
|
|
325
332
|
</div>
|
|
326
333
|
|
|
327
334
|
<div className="ai-result-block">
|
|
328
|
-
<h3 className="ai-result-subtitle">
|
|
335
|
+
<h3 className="ai-result-subtitle">
|
|
336
|
+
{t("common.result", "Result")}
|
|
337
|
+
</h3>
|
|
329
338
|
<div className="ai-result-content">
|
|
330
339
|
{analysisResult.content}
|
|
331
340
|
</div>
|
|
@@ -122,7 +122,10 @@ export function AiImageButton({
|
|
|
122
122
|
if (!generatedImage || !onImageSave) return;
|
|
123
123
|
try {
|
|
124
124
|
await onImageSave(generatedImage.url);
|
|
125
|
-
onToast?.({
|
|
125
|
+
onToast?.({
|
|
126
|
+
type: "success",
|
|
127
|
+
message: t("ai.image.savedSuccess", "Image saved"),
|
|
128
|
+
});
|
|
126
129
|
} catch (_error) {
|
|
127
130
|
onToast?.({
|
|
128
131
|
type: "error",
|
|
@@ -174,7 +177,10 @@ export function AiImageButton({
|
|
|
174
177
|
});
|
|
175
178
|
onToast?.({
|
|
176
179
|
type: "success",
|
|
177
|
-
message: t(
|
|
180
|
+
message: t(
|
|
181
|
+
"ai.image.generatedSuccess",
|
|
182
|
+
"Image generated successfully"
|
|
183
|
+
),
|
|
178
184
|
});
|
|
179
185
|
|
|
180
186
|
// Afficher le toast de coût même en mode dev
|
|
@@ -29,7 +29,9 @@ export function AiModelSelect({
|
|
|
29
29
|
disabled={disabled}
|
|
30
30
|
data-ai-model-select
|
|
31
31
|
>
|
|
32
|
-
<option value="">
|
|
32
|
+
<option value="">
|
|
33
|
+
{t("ai.select.modelPlaceholder", "Select a model")}
|
|
34
|
+
</option>
|
|
33
35
|
{models.map((model) => (
|
|
34
36
|
<option key={model.id} value={model.id}>
|
|
35
37
|
{model.name}
|
|
@@ -570,7 +570,10 @@ function AiPromptPanelInternal({
|
|
|
570
570
|
AI Model
|
|
571
571
|
</label>
|
|
572
572
|
{isModelsLoading ? (
|
|
573
|
-
<span
|
|
573
|
+
<span
|
|
574
|
+
className="ai-inline-skeleton"
|
|
575
|
+
aria-hidden="true"
|
|
576
|
+
/>
|
|
574
577
|
) : effectiveAvailableModels.length > 0 ? (
|
|
575
578
|
<button
|
|
576
579
|
onClick={() => setIsModelManagementOpen(true)}
|
|
@@ -747,17 +750,17 @@ function AiPromptPanelInternal({
|
|
|
747
750
|
onChange={(e) => setPrompt(e.target.value)}
|
|
748
751
|
onFocus={() => setPromptFocused(true)}
|
|
749
752
|
onBlur={() => setPromptFocused(false)}
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
753
|
+
placeholder={
|
|
754
|
+
sourceText
|
|
755
|
+
? t(
|
|
756
|
+
"prompt.modal.promptPlaceholderWithSource",
|
|
757
|
+
"Enter your AI prompt... e.g., 'Fix grammar', 'Make it more professional', 'Translate to English'"
|
|
758
|
+
)
|
|
759
|
+
: t(
|
|
760
|
+
"prompt.modal.promptPlaceholderNoSource",
|
|
761
|
+
"Enter your AI prompt... e.g., 'Write a blog post about AI', 'Generate product description'"
|
|
762
|
+
)
|
|
763
|
+
}
|
|
761
764
|
rows={6}
|
|
762
765
|
style={{
|
|
763
766
|
...aiStyles.textarea,
|
|
@@ -889,7 +892,10 @@ function AiPromptPanelInternal({
|
|
|
889
892
|
}}
|
|
890
893
|
>
|
|
891
894
|
{Array.from({ length: 4 }).map((_, idx) => (
|
|
892
|
-
<div
|
|
895
|
+
<div
|
|
896
|
+
key={`prompt-skeleton-${idx}`}
|
|
897
|
+
className="ai-list-skeleton"
|
|
898
|
+
>
|
|
893
899
|
<div className="ai-list-skeleton__line ai-list-skeleton__line--lg" />
|
|
894
900
|
<div className="ai-list-skeleton__line ai-list-skeleton__line--md" />
|
|
895
901
|
</div>
|
|
@@ -1260,7 +1266,10 @@ function AiPromptPanelInternal({
|
|
|
1260
1266
|
{isModelsLoading ? (
|
|
1261
1267
|
<>
|
|
1262
1268
|
{Array.from({ length: 4 }).map((_, idx) => (
|
|
1263
|
-
<div
|
|
1269
|
+
<div
|
|
1270
|
+
key={`model-skeleton-${idx}`}
|
|
1271
|
+
className="ai-list-skeleton"
|
|
1272
|
+
>
|
|
1264
1273
|
<div className="ai-list-skeleton__line ai-list-skeleton__line--lg" />
|
|
1265
1274
|
<div className="ai-list-skeleton__line ai-list-skeleton__line--md" />
|
|
1266
1275
|
</div>
|
|
@@ -1365,35 +1374,35 @@ function AiPromptPanelInternal({
|
|
|
1365
1374
|
);
|
|
1366
1375
|
})}
|
|
1367
1376
|
{!isModelsLoading &&
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1377
|
+
effectiveAvailableModels.filter((model) => {
|
|
1378
|
+
if (model.category !== modelCategory) return false;
|
|
1379
|
+
if (!modelSearchQuery.trim()) return true;
|
|
1380
|
+
const query = modelSearchQuery.toLowerCase();
|
|
1381
|
+
return (
|
|
1382
|
+
model.name.toLowerCase().includes(query) ||
|
|
1383
|
+
model.provider.toLowerCase().includes(query) ||
|
|
1384
|
+
model.description?.toLowerCase().includes(query)
|
|
1385
|
+
);
|
|
1386
|
+
}).length === 0 && (
|
|
1387
|
+
<div
|
|
1388
|
+
style={{
|
|
1389
|
+
textAlign: "center",
|
|
1390
|
+
padding: "32px 16px",
|
|
1391
|
+
color: "var(--ai-text-tertiary)",
|
|
1392
|
+
fontSize: "14px",
|
|
1393
|
+
}}
|
|
1394
|
+
>
|
|
1395
|
+
{modelSearchQuery.trim()
|
|
1396
|
+
? t(
|
|
1397
|
+
"prompt.modal.noModelMatch",
|
|
1398
|
+
"No model matches your search"
|
|
1399
|
+
)
|
|
1400
|
+
: t(
|
|
1401
|
+
"prompt.modal.noModelAvailable",
|
|
1402
|
+
"No models available"
|
|
1403
|
+
)}
|
|
1404
|
+
</div>
|
|
1405
|
+
)}
|
|
1397
1406
|
</div>
|
|
1398
1407
|
</div>
|
|
1399
1408
|
|
|
@@ -229,8 +229,7 @@ export function AiStatusButton({
|
|
|
229
229
|
: undefined;
|
|
230
230
|
const requiresApiKeySelection =
|
|
231
231
|
lbStatus === "ready" && !hasApiKeySelected && apiKeys.length > 0;
|
|
232
|
-
const isApiKeyAuthMode =
|
|
233
|
-
authTypeValue === "api_key";
|
|
232
|
+
const isApiKeyAuthMode = authTypeValue === "api_key";
|
|
234
233
|
|
|
235
234
|
const [tooltipStyle, setTooltipStyle] = useState<Record<string, string>>({});
|
|
236
235
|
|
|
@@ -328,11 +327,11 @@ export function AiStatusButton({
|
|
|
328
327
|
|
|
329
328
|
const hasApiKeyMeta = Boolean(
|
|
330
329
|
effectiveStatus?.apiKey?.name ||
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
330
|
+
effectiveStatus?.api_key?.name ||
|
|
331
|
+
effectiveStatus?.apiKey?.env ||
|
|
332
|
+
effectiveStatus?.api_key?.env ||
|
|
333
|
+
effectiveStatus?.apiKey?.rate_limit_rpm ||
|
|
334
|
+
effectiveStatus?.api_key?.rate_limit_rpm
|
|
336
335
|
);
|
|
337
336
|
const hasBalanceMeta = Boolean(effectiveStatus?.balance);
|
|
338
337
|
const hasStorageMeta = Boolean(effectiveStatus?.storage);
|
|
@@ -422,10 +421,14 @@ export function AiStatusButton({
|
|
|
422
421
|
{lbStatus === "ready" && user ? (
|
|
423
422
|
<>
|
|
424
423
|
<div className="ai-popover-body">
|
|
425
|
-
<div className="ai-popover-header">
|
|
424
|
+
<div className="ai-popover-header">
|
|
425
|
+
{t("status.title", "API Status")}
|
|
426
|
+
</div>
|
|
426
427
|
<div className="ai-popover-section ai-popover-section--first">
|
|
427
428
|
<div className="ai-popover-row">
|
|
428
|
-
<span className="ai-popover-label">
|
|
429
|
+
<span className="ai-popover-label">
|
|
430
|
+
{t("status.user", "User")}
|
|
431
|
+
</span>
|
|
429
432
|
<span
|
|
430
433
|
className="ai-popover-value ai-truncate"
|
|
431
434
|
style={{ maxWidth: 200 }}
|
|
@@ -437,7 +440,9 @@ export function AiStatusButton({
|
|
|
437
440
|
|
|
438
441
|
<div className="ai-popover-section">
|
|
439
442
|
<div className="ai-popover-row">
|
|
440
|
-
<span className="ai-popover-label">
|
|
443
|
+
<span className="ai-popover-label">
|
|
444
|
+
{t("status.apiKey", "API Key")}
|
|
445
|
+
</span>
|
|
441
446
|
<div className="ai-row">
|
|
442
447
|
{lbIsLoadingStatus || isImplicitStatusLoading ? (
|
|
443
448
|
<div className="ai-kv-skeleton ai-kv-skeleton--110" />
|
|
@@ -468,7 +473,9 @@ export function AiStatusButton({
|
|
|
468
473
|
</div>
|
|
469
474
|
|
|
470
475
|
<div className="ai-popover-row">
|
|
471
|
-
<span className="ai-popover-label">
|
|
476
|
+
<span className="ai-popover-label">
|
|
477
|
+
{t("status.env", "Env")}
|
|
478
|
+
</span>
|
|
472
479
|
{(lbIsLoadingStatus || isImplicitStatusLoading) &&
|
|
473
480
|
!effectiveStatus?.apiKey?.env ? (
|
|
474
481
|
<div className="ai-kv-skeleton ai-kv-skeleton--48" />
|
|
@@ -482,7 +489,9 @@ export function AiStatusButton({
|
|
|
482
489
|
</div>
|
|
483
490
|
|
|
484
491
|
<div className="ai-popover-row">
|
|
485
|
-
<span className="ai-popover-label">
|
|
492
|
+
<span className="ai-popover-label">
|
|
493
|
+
{t("status.rateLimit", "Rate Limit")}
|
|
494
|
+
</span>
|
|
486
495
|
{(lbIsLoadingStatus || isImplicitStatusLoading) &&
|
|
487
496
|
!effectiveStatus?.apiKey?.rate_limit_rpm ? (
|
|
488
497
|
<div className="ai-kv-skeleton ai-kv-skeleton--92" />
|
|
@@ -490,14 +499,16 @@ export function AiStatusButton({
|
|
|
490
499
|
<span className="ai-popover-value">
|
|
491
500
|
{effectiveStatus?.apiKey?.rate_limit_rpm ||
|
|
492
501
|
effectiveStatus?.api_key?.rate_limit_rpm ||
|
|
493
|
-
|
|
502
|
+
0}{" "}
|
|
494
503
|
req/min
|
|
495
504
|
</span>
|
|
496
505
|
)}
|
|
497
506
|
</div>
|
|
498
507
|
|
|
499
508
|
<div className="ai-popover-row">
|
|
500
|
-
<span className="ai-popover-label">
|
|
509
|
+
<span className="ai-popover-label">
|
|
510
|
+
{t("status.auth", "Auth")}
|
|
511
|
+
</span>
|
|
501
512
|
<span className="ai-popover-value">
|
|
502
513
|
{lbIsLoadingStatus || isImplicitStatusLoading
|
|
503
514
|
? "..."
|
|
@@ -513,7 +524,9 @@ export function AiStatusButton({
|
|
|
513
524
|
{t("status.wallet", "Wallet")}
|
|
514
525
|
</div>
|
|
515
526
|
<div className="ai-popover-row">
|
|
516
|
-
<span className="ai-popover-label">
|
|
527
|
+
<span className="ai-popover-label">
|
|
528
|
+
{t("status.total", "Total")}
|
|
529
|
+
</span>
|
|
517
530
|
{(lbIsLoadingStatus || isImplicitStatusLoading) &&
|
|
518
531
|
!effectiveStatus?.balance ? (
|
|
519
532
|
<div className="ai-row">
|
|
@@ -536,7 +549,9 @@ export function AiStatusButton({
|
|
|
536
549
|
{t("status.storage", "Storage")}
|
|
537
550
|
</div>
|
|
538
551
|
<div className="ai-popover-row">
|
|
539
|
-
<span className="ai-popover-label">
|
|
552
|
+
<span className="ai-popover-label">
|
|
553
|
+
{t("status.total", "Total")}
|
|
554
|
+
</span>
|
|
540
555
|
{lbIsLoadingStorage || isImplicitStorageLoading ? (
|
|
541
556
|
<div className="ai-row">
|
|
542
557
|
<div className="ai-kv-skeleton ai-kv-skeleton--120" />
|
|
@@ -564,8 +579,8 @@ export function AiStatusButton({
|
|
|
564
579
|
type="button"
|
|
565
580
|
className="ai-status-action-btn"
|
|
566
581
|
onClick={() => window.open(item.href, "_blank")}
|
|
567
|
-
|
|
568
|
-
|
|
582
|
+
title={label}
|
|
583
|
+
data-ai-tip={label}
|
|
569
584
|
>
|
|
570
585
|
<Icon size={17} />
|
|
571
586
|
</button>
|
|
@@ -602,7 +617,10 @@ export function AiStatusButton({
|
|
|
602
617
|
{t("status.lastbrainAuth", "LastBrain Authentication")}
|
|
603
618
|
</div>
|
|
604
619
|
<p className="ai-signin-subtitle" style={{ marginTop: 0 }}>
|
|
605
|
-
{t(
|
|
620
|
+
{t(
|
|
621
|
+
"status.connectToAccess",
|
|
622
|
+
"Sign in to access AI features."
|
|
623
|
+
)}
|
|
606
624
|
</p>
|
|
607
625
|
<button
|
|
608
626
|
type="button"
|
|
@@ -122,11 +122,11 @@ export function LBApiKeySelector({
|
|
|
122
122
|
{t("common.active", "Active")}
|
|
123
123
|
</span>
|
|
124
124
|
) : (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
<span className="ai-pill ai-pill--cost">
|
|
126
|
+
<XCircle size={12} />
|
|
127
|
+
{t("common.inactive", "Inactive")}
|
|
128
|
+
</span>
|
|
129
|
+
)}
|
|
130
130
|
</label>
|
|
131
131
|
);
|
|
132
132
|
})}
|
|
@@ -43,9 +43,7 @@ export function LBConnectButton({
|
|
|
43
43
|
|
|
44
44
|
const connectLabel = label || t("auth.signIn", "Sign in");
|
|
45
45
|
const buttonLabel =
|
|
46
|
-
status === "ready" && user
|
|
47
|
-
? t("auth.signOut", "Sign out")
|
|
48
|
-
: connectLabel;
|
|
46
|
+
status === "ready" && user ? t("auth.signOut", "Sign out") : connectLabel;
|
|
49
47
|
|
|
50
48
|
return (
|
|
51
49
|
<>
|
|
@@ -64,9 +64,7 @@ export function LBSigninModal({ isOpen, onClose }: LBSigninModalProps) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
if (!fetchApiKeys || !result.accessToken) {
|
|
67
|
-
setError(
|
|
68
|
-
t("auth.modal.tokenMissing", "Access token unavailable")
|
|
69
|
-
);
|
|
67
|
+
setError(t("auth.modal.tokenMissing", "Access token unavailable"));
|
|
70
68
|
return;
|
|
71
69
|
}
|
|
72
70
|
|
|
@@ -76,9 +74,7 @@ export function LBSigninModal({ isOpen, onClose }: LBSigninModalProps) {
|
|
|
76
74
|
setShowKeySelector(true);
|
|
77
75
|
} catch (keyError) {
|
|
78
76
|
console.error("Failed to fetch API keys:", keyError);
|
|
79
|
-
setError(
|
|
80
|
-
t("auth.modal.apiKeysFetchError", "Failed to fetch API keys")
|
|
81
|
-
);
|
|
77
|
+
setError(t("auth.modal.apiKeysFetchError", "Failed to fetch API keys"));
|
|
82
78
|
}
|
|
83
79
|
} catch (err) {
|
|
84
80
|
setError(
|
|
@@ -186,7 +182,10 @@ export function LBSigninModal({ isOpen, onClose }: LBSigninModalProps) {
|
|
|
186
182
|
required
|
|
187
183
|
autoFocus
|
|
188
184
|
autoComplete="email"
|
|
189
|
-
placeholder={t(
|
|
185
|
+
placeholder={t(
|
|
186
|
+
"auth.modal.emailPlaceholder",
|
|
187
|
+
"your@email.com"
|
|
188
|
+
)}
|
|
190
189
|
/>
|
|
191
190
|
</div>
|
|
192
191
|
</div>
|
|
@@ -210,7 +209,10 @@ export function LBSigninModal({ isOpen, onClose }: LBSigninModalProps) {
|
|
|
210
209
|
onChange={(e) => setPassword(e.target.value)}
|
|
211
210
|
required
|
|
212
211
|
autoComplete="current-password"
|
|
213
|
-
placeholder={t(
|
|
212
|
+
placeholder={t(
|
|
213
|
+
"auth.modal.passwordPlaceholder",
|
|
214
|
+
"••••••••"
|
|
215
|
+
)}
|
|
214
216
|
/>
|
|
215
217
|
</div>
|
|
216
218
|
</div>
|
|
@@ -46,14 +46,18 @@ export interface I18nProviderProps {
|
|
|
46
46
|
lang?: LBSupportedLang;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export function I18nProvider({
|
|
49
|
+
export function I18nProvider({
|
|
50
|
+
children,
|
|
51
|
+
lang = defaultLang,
|
|
52
|
+
}: I18nProviderProps) {
|
|
50
53
|
const safeLang: LBSupportedLang = dictionaries[lang] ? lang : defaultLang;
|
|
51
54
|
|
|
52
55
|
const value = useMemo<I18nContextValue>(() => {
|
|
53
56
|
const dict = dictionaries[safeLang] || dictionaries[defaultLang];
|
|
54
57
|
|
|
55
58
|
const t = (key: string, fallback?: string, params?: TranslateParams) => {
|
|
56
|
-
const template =
|
|
59
|
+
const template =
|
|
60
|
+
dict[key] || dictionaries[defaultLang][key] || fallback || key;
|
|
57
61
|
if (!params) return template;
|
|
58
62
|
return template.replace(/\{(\w+)\}/g, (_, p: string) =>
|
|
59
63
|
params[p] !== undefined ? String(params[p]) : `{${p}}`
|
|
@@ -14,19 +14,25 @@ export function useLoadingTimer(active: boolean) {
|
|
|
14
14
|
|
|
15
15
|
useEffect(() => {
|
|
16
16
|
if (!active) {
|
|
17
|
-
setSeconds(0);
|
|
18
|
-
return;
|
|
17
|
+
const timeoutId = window.setTimeout(() => setSeconds(0), 0);
|
|
18
|
+
return () => window.clearTimeout(timeoutId);
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
const
|
|
20
|
+
|
|
21
|
+
const resetId = window.setTimeout(() => setSeconds(0), 0);
|
|
22
|
+
const intervalId = window.setInterval(() => {
|
|
22
23
|
setSeconds((prev) => prev + 1);
|
|
23
24
|
}, 1000);
|
|
24
|
-
|
|
25
|
+
|
|
26
|
+
return () => {
|
|
27
|
+
window.clearTimeout(resetId);
|
|
28
|
+
window.clearInterval(intervalId);
|
|
29
|
+
};
|
|
25
30
|
}, [active]);
|
|
26
31
|
|
|
32
|
+
const displaySeconds = active ? seconds : 0;
|
|
33
|
+
|
|
27
34
|
return {
|
|
28
|
-
seconds,
|
|
29
|
-
formatted: formatElapsed(
|
|
35
|
+
seconds: displaySeconds,
|
|
36
|
+
formatted: formatElapsed(displaySeconds),
|
|
30
37
|
};
|
|
31
38
|
}
|
|
32
|
-
|