diff --git a/app/components/auth.tsx b/app/components/auth.tsx index c46e8251346..8aa862feef9 100644 --- a/app/components/auth.tsx +++ b/app/components/auth.tsx @@ -7,7 +7,6 @@ import { useAccessStore } from "../store"; import Locale from "../locales"; import BotIcon from "../icons/bot.svg"; -import { useEffect } from "react"; import { getClientConfig } from "../config/client"; export function AuthPage() { @@ -18,13 +17,6 @@ export function AuthPage() { const resetAccessCode = () => { access.updateCode(""); access.updateToken(""); }; // Reset access code to empty string const goPrivacy = () => navigate(Path.PrivacyPage); - useEffect(() => { - if (getClientConfig()?.isApp) { - navigate(Path.Settings); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - return (
@@ -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": {