Skip to content
This repository has been archived by the owner on Sep 15, 2024. It is now read-only.

Client App [Tauri] #27

Merged
merged 10 commits into from
Oct 1, 2023
33 changes: 14 additions & 19 deletions app/components/auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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 (
<div className={styles["auth-page"]}>
<div className={`no-dark ${styles["auth-logo"]}`}>
Expand All @@ -34,16 +26,19 @@ export function AuthPage() {
<div className={styles["auth-title"]}>{Locale.Auth.Title}</div>
<div className={styles["auth-tips"]}>{Locale.Auth.Tips}</div>

<input
className={styles["auth-input"]}
type="password"
placeholder={Locale.Auth.Input}
value={access.accessCode}
onChange={(e) => {
access.updateCode(e.currentTarget.value);
}}
/>
{!access.hideUserApiKey ? (
{!getClientConfig()?.isApp && ( // Conditionally render the input access code based on whether it's an app
<input
className={styles["auth-input"]}
type="password"
placeholder={Locale.Auth.Input}
value={access.accessCode}
onChange={(e) => {
access.updateCode(e.currentTarget.value);
}}
/>
)}

{getClientConfig()?.isApp && ( // Conditionally render the input access token based on whether it's an app
<>
<div className={styles["auth-tips"]}>{Locale.Auth.SubTips}</div>
<input
Expand All @@ -56,7 +51,7 @@ export function AuthPage() {
}}
/>
</>
) : null}
)}

<div className={styles["auth-actions"]}>
<IconButton
Expand Down
16 changes: 13 additions & 3 deletions app/components/changelog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,21 @@ export function ChangeLog(props: { onClose?: () => 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`;
}
Expand Down
80 changes: 62 additions & 18 deletions app/components/exporter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 (
<>
<PreviewActions
Expand Down
6 changes: 3 additions & 3 deletions app/config/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ export const getBuildConfig = () => {
.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
.execSync('git log --pretty=format:"%an" -n 1')
.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(
Expand Down
20 changes: 18 additions & 2 deletions app/config/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
};
}
}

Expand Down
8 changes: 7 additions & 1 deletion app/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ declare module "*.svg";

declare interface Window {
__TAURI__?: {
[x: string]: any;
writeText(text: string): Promise<void>;
invoke(command: string, payload?: Record<string, unknown>): Promise<any>;
dialog: {
save(options?: Record<string, unknown>): Promise<string | null>;
};
fs: {
writeBinaryFile(path: string, data: Uint8Array): Promise<void>;
};
};
}
2 changes: 1 addition & 1 deletion app/locales/cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion app/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
11 changes: 9 additions & 2 deletions app/store/sync.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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,
Expand All @@ -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() {
Expand Down
11 changes: 6 additions & 5 deletions app/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getClientConfig } from "./config/client";
import { useEffect, useState } from "react";
import { showToast } from "./components/ui-lib";
import Locale from "./locales";
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
"startDragging": true,
"unmaximize": true,
"unminimize": true
},
"fs": {
"all": true
}
},
"bundle": {
Expand Down