@@ -34,16 +26,19 @@ export function AuthPage() {
{Locale.Auth.Title}
{Locale.Auth.Tips}
-
{
- access.updateCode(e.currentTarget.value);
- }}
- />
- {!access.hideUserApiKey ? (
+ {!getClientConfig()?.isApp && ( // Conditionally render the input access code based on whether it's an app
+
{
+ access.updateCode(e.currentTarget.value);
+ }}
+ />
+ )}
+
+ {getClientConfig()?.isApp && ( // Conditionally render the input access token based on whether it's an app
<>
{Locale.Auth.SubTips}
>
- ) : null}
+ )}
void }) {
const fetchData = async () => {
const commitInfo = getClientConfig();
- let table = `## 🚀 What's Changed ? ${commitInfo?.commitDate ? new Date(parseInt(commitInfo.commitDate)).toLocaleString() : 'Unknown Date'} 🗓️\n`;
+ let table = `## 🚀 What's Changed ? ${
+ commitInfo?.commitDate
+ ? new Date(parseInt(commitInfo.commitDate)).toLocaleString()
+ : "Unknown Date"
+ } 🗓️\n`;
if (commitInfo?.commitMessage.description) {
- const changes = commitInfo?.commitMessage.description.map((change: string) => `\n\n\n ${change}\n\n`).join("\n\n\n");
- table += `\n\n\n ${commitInfo?.commitMessage.summary}\n\n\n${changes}\n\n\n`;
+ let changes: string[] = commitInfo.commitMessage.description;
+ if (getClientConfig()?.isApp && changes.length > 10) {
+ changes = changes.slice(0, 10); // Limit to 10 messages for isApp
+ }
+ const changesFormatted = changes
+ .map((change: string) => `\n\n\n ${change}\n\n`)
+ .join("\n\n\n");
+ table += `\n\n\n ${commitInfo?.commitMessage.summary}\n\n\n${changesFormatted}\n\n\n`;
} else {
table += `###${commitInfo?.commitMessage.summary}###\nNo changes\n\n`;
}
diff --git a/app/components/exporter.tsx b/app/components/exporter.tsx
index 9cef7d3a6fe..0611b2606df 100644
--- a/app/components/exporter.tsx
+++ b/app/components/exporter.tsx
@@ -433,26 +433,46 @@ export function ImagePreviewer(props: {
const isMobile = useMobileScreen();
- const download = () => {
+ const download = async () => {
showToast(Locale.Export.Image.Toast);
const dom = previewRef.current;
if (!dom) return;
- toPng(dom)
- .then((blob) => {
- if (!blob) return;
-
- if (isMobile || getClientConfig()?.isApp) {
- showImageModal(blob);
+
+ const isApp = getClientConfig()?.isApp;
+
+ try {
+ const blob = await toPng(dom);
+ if (!blob) return;
+
+ if (isMobile || (isApp && window.__TAURI__)) {
+ if (isApp && window.__TAURI__) {
+ const result = await window.__TAURI__.dialog.save({
+ defaultPath: `${props.topic}.png`,
+ });
+
+ if (result !== null) {
+ const response = await fetch(blob);
+ const buffer = await response.arrayBuffer();
+ const uint8Array = new Uint8Array(buffer);
+ await window.__TAURI__.fs.writeBinaryFile(result, uint8Array);
+ showToast(Locale.Download.Success);
+ } else {
+ showToast(Locale.Download.Failed);
+ }
} else {
- const link = document.createElement("a");
- link.download = `${props.topic}.png`;
- link.href = blob;
- link.click();
- refreshPreview();
+ showImageModal(blob);
}
- })
- .catch((e) => console.log("[Export Image] ", e));
- };
+ } else {
+ const link = document.createElement("a");
+ link.download = `${props.topic}.png`;
+ link.href = blob;
+ link.click();
+ refreshPreview();
+ }
+ } catch (error) {
+ showToast(Locale.Download.Failed);
+ }
+ };
const refreshPreview = () => {
const dom = previewRef.current;
@@ -566,14 +586,38 @@ export function MarkdownPreviewer(props: {
const copy = () => {
copyToClipboard(mdText);
};
- const download = () => {
+ const download = async () => {
+ const isApp = getClientConfig()?.isApp;
const blob = new Blob([mdText], { type: "text/markdown" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `${props.topic}.md`;
- link.click();
- };
+
+ if (isApp && window.__TAURI__) {
+ try {
+ const result = await window.__TAURI__.dialog.save({
+ defaultPath: `${props.topic}.md`,
+ });
+
+ if (result !== null) {
+ const response = await fetch(url);
+ const buffer = await response.arrayBuffer();
+ const uint8Array = new Uint8Array(buffer);
+ await window.__TAURI__.fs.writeBinaryFile(result, uint8Array);
+ showToast(Locale.Download.Success);
+ } else {
+ showToast(Locale.Download.Failed);
+ }
+ } catch (error) {
+ showToast(Locale.Download.Failed);
+ }
+ } else {
+ link.click();
+ }
+
+ URL.revokeObjectURL(url);
+ };
return (
<>
{
.toString()
.trim();
const commitHash: string = childProcess
- .execSync('git log --pretty=format:"%H" -n 1')
+ .execSync('git log --pretty=format:"%H" -n 10')
.toString()
.trim();
const commitMessage: string = childProcess
- .execSync('git log --pretty=format:"%B" -n 5')
+ .execSync('git log --pretty=format:"%B" -n 10')
.toString()
.trim();
const Author: string = childProcess
@@ -25,7 +25,7 @@ export const getBuildConfig = () => {
.toString()
.trim();
const coAuthorLine: string = childProcess
- .execSync('git log --format="%h %(trailers:key=Co-authored-by)" -n 5')
+ .execSync('git log --format="%h %(trailers:key=Co-authored-by)" -n 10')
.toString()
.trim();
const coAuthorMatch: RegExpMatchArray | null = coAuthorLine.match(
diff --git a/app/config/client.ts b/app/config/client.ts
index da582a3e858..963106130b9 100644
--- a/app/config/client.ts
+++ b/app/config/client.ts
@@ -3,12 +3,28 @@ import { BuildConfig, getBuildConfig } from "./build";
export function getClientConfig() {
if (typeof document !== "undefined") {
// client side
- return JSON.parse(queryMeta("config")) as BuildConfig;
+ const buildConfig = JSON.parse(queryMeta("config")) as BuildConfig;
+ const commitMessage = buildConfig.commitMessage?.description?.slice(0, 10);
+ return {
+ ...buildConfig,
+ commitMessage: {
+ ...buildConfig.commitMessage,
+ description: commitMessage,
+ },
+ };
}
if (typeof process !== "undefined") {
// server side
- return getBuildConfig();
+ const buildConfig = getBuildConfig();
+ const commitMessage = buildConfig.commitMessage?.description?.slice(0, 10);
+ return {
+ ...buildConfig,
+ commitMessage: {
+ ...buildConfig.commitMessage,
+ description: commitMessage,
+ },
+ };
}
}
diff --git a/app/global.d.ts b/app/global.d.ts
index a75d9789a25..9282b9d303a 100644
--- a/app/global.d.ts
+++ b/app/global.d.ts
@@ -12,7 +12,13 @@ declare module "*.svg";
declare interface Window {
__TAURI__?: {
- [x: string]: any;
writeText(text: string): Promise;
+ invoke(command: string, payload?: Record): Promise;
+ dialog: {
+ save(options?: Record): Promise;
+ };
+ fs: {
+ writeBinaryFile(path: string, data: Uint8Array): Promise;
+ };
};
}
diff --git a/app/locales/cn.ts b/app/locales/cn.ts
index db52644f197..6a41c292abf 100644
--- a/app/locales/cn.ts
+++ b/app/locales/cn.ts
@@ -7,7 +7,7 @@ const cn = {
WIP: "该功能仍在开发中……",
Error: {
Unauthorized: isApp
- ? "检测到无效 API Key,请前往[设置](/#/settings)页检查 API Key 是否配置正确。"
+ ? "未经授权的访问,请在 [auth](/#/auth) 页面输入您的 OpenAI API Key。"
: "访问密码不正确或为空,请前往[登录](/#/auth)页输入正确的访问密码,或者在[设置](/#/settings)页填入你自己的 OpenAI API Key。",
Content_Policy: {
Title:
diff --git a/app/locales/en.ts b/app/locales/en.ts
index 587768a65b8..eecf937a464 100644
--- a/app/locales/en.ts
+++ b/app/locales/en.ts
@@ -9,7 +9,7 @@ const en: LocaleType = {
WIP: "Coming Soon...",
Error: {
Unauthorized: isApp
- ? "Invalid API Key, please check it in [Settings](/#/settings) page."
+ ? "Unauthorized access, please enter your OpenAI API Key in [auth](/#/auth) page."
: "Unauthorized access, please enter access code in [auth](/#/auth) page, or enter your OpenAI API Key.",
Content_Policy: {
Title:
diff --git a/app/store/sync.ts b/app/store/sync.ts
index 3fca3bd35bf..499a753e1f5 100644
--- a/app/store/sync.ts
+++ b/app/store/sync.ts
@@ -1,3 +1,4 @@
+import { getClientConfig } from "../config/client";
import { Updater } from "../typing";
import { ApiPath, STORAGE_KEY, StoreKey } from "../constant";
import { createPersistStore } from "../utils/store";
@@ -63,6 +64,8 @@ const DEFAULT_SYNC_STATE = {
syncing: false,
lockclient: false,
};
+// alternative fix for tauri
+const isApp = !!getClientConfig()?.isApp;
export const useSyncStore = createPersistStore(
DEFAULT_SYNC_STATE,
@@ -82,8 +85,12 @@ export const useSyncStore = createPersistStore(
export() {
const state = getLocalAppState();
- const fileName = `Backup-${new Date().toLocaleString()}`;
- downloadAs(state, fileName);
+ const datePart = isApp
+ ? `${new Date().toLocaleDateString().replace(/\//g, '_')} ${new Date().toLocaleTimeString().replace(/:/g, '_')}`
+ : new Date().toLocaleString();
+
+ const fileName = `Backup-${datePart}`;
+ downloadAs((state), fileName);
},
async import() {
diff --git a/app/utils.ts b/app/utils.ts
index 10c3de2b1af..ab464193ccd 100644
--- a/app/utils.ts
+++ b/app/utils.ts
@@ -1,3 +1,4 @@
+import { getClientConfig } from "./config/client";
import { useEffect, useState } from "react";
import { showToast } from "./components/ui-lib";
import Locale from "./locales";
@@ -6,9 +7,12 @@ export function trimTopic(topic: string) {
return topic.replace(/[,。!?”“"、,.!?]*$/, "");
}
+const isApp = !!getClientConfig()?.isApp;
+
export async function copyToClipboard(text: string) {
+
try {
- if (window.__TAURI__) {
+ if (isApp && window.__TAURI__) {
window.__TAURI__.writeText(text);
} else {
await navigator.clipboard.writeText(text);
@@ -44,10 +48,7 @@ export async function downloadAs(text: object, filename: string) {
});
if (result !== null) {
- await window.__TAURI__.fs.writeBinaryFile(
- result,
- Array.from(uint8Array),
- );
+ await window.__TAURI__.fs.writeBinaryFile(result, Uint8Array.from(uint8Array));
showToast(Locale.Download.Success);
} else {
showToast(Locale.Download.Failed);
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 77b02a3bae8..e8172ae67d0 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -44,6 +44,9 @@
"startDragging": true,
"unmaximize": true,
"unminimize": true
+ },
+ "fs": {
+ "all": true
}
},
"bundle": {