Skip to content

Commit 884d06e

Browse files
committed
feat(SharePage): enhance sharing functionality with theme and language support
1 parent 5481857 commit 884d06e

3 files changed

Lines changed: 94 additions & 8 deletions

File tree

components/routes/FileManager.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ import {
4141
TimeFilter,
4242
} from "../../types";
4343
import {
44+
CONFIG_STORAGE_KEY,
45+
THEME_STORAGE_KEY,
4446
CHUNK_SIZE,
4547
formatBytes,
4648
t,
@@ -74,9 +76,6 @@ import { PendingFileItem } from "../PendingFileItem";
7476
import { FilterMenu } from "../FilterMenu";
7577
import { SortMenu } from "../SortMenu";
7678

77-
const CONFIG_STORAGE_KEY = "telecloud_config";
78-
const THEME_STORAGE_KEY = "telecloud_theme";
79-
8079
// Breadcrumb item type
8180
interface Breadcrumb {
8281
id: number | null;

components/routes/SharePage.tsx

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
import React, { useMemo, useState } from "react";
1+
import React, { useMemo, useState, useEffect } from "react";
22
import { useSearchParams } from "react-router-dom";
33
import { Download, File as FileIcon, Loader2, AlertCircle } from "lucide-react";
44
import { AppConfig, WorkerResponse } from "../../types";
55
import { DEFAULT_WORKER_URL } from "../../types";
6+
import {
7+
CONFIG_STORAGE_KEY,
8+
THEME_STORAGE_KEY,
9+
t,
10+
DEFAULT_LANG,
11+
} from "../../constants";
612

713
// Helper to decode the share payload
814
// payload = base64(json({ w: workerUrl, f: fileId, n: fileName }))
@@ -21,6 +27,55 @@ export function SharePage() {
2127
const [searchParams] = useSearchParams();
2228
const shareParam = searchParams.get("s");
2329

30+
// Theme State
31+
type Theme = "light" | "dark" | "system";
32+
const [theme, setTheme] = useState<Theme>(() => {
33+
const saved = localStorage.getItem(THEME_STORAGE_KEY);
34+
// Migration: if saved is boolean (old), convert to 'light'/'dark'
35+
if (saved === "true") return "dark";
36+
if (saved === "false") return "light";
37+
// Remove quotes if they exist (JSON.stringify adds them)
38+
const cleanSaved = saved ? saved.replace(/"/g, "") : null;
39+
return (cleanSaved as Theme) || "system";
40+
});
41+
useEffect(() => {
42+
const applyTheme = () => {
43+
const isDark =
44+
theme === "dark" ||
45+
(theme === "system" &&
46+
window.matchMedia("(prefers-color-scheme: dark)").matches);
47+
48+
if (isDark) {
49+
document.documentElement.classList.add("dark");
50+
} else {
51+
document.documentElement.classList.remove("dark");
52+
}
53+
};
54+
55+
applyTheme();
56+
localStorage.setItem(THEME_STORAGE_KEY, theme);
57+
58+
if (theme === "system") {
59+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
60+
const handler = () => applyTheme();
61+
mediaQuery.addEventListener("change", handler);
62+
return () => mediaQuery.removeEventListener("change", handler);
63+
}
64+
}, [theme]);
65+
66+
// Lang
67+
const [language, setLanguage] = useState(() => {
68+
const saved = localStorage.getItem(CONFIG_STORAGE_KEY);
69+
return saved
70+
? JSON.parse(saved).language
71+
: (navigator.languages?.[0] || navigator.language).split("-")[0] ||
72+
DEFAULT_LANG;
73+
});
74+
useEffect(() => {
75+
document.documentElement.lang = language;
76+
localStorage.setItem(CONFIG_STORAGE_KEY, JSON.stringify({ language }));
77+
}, [language]);
78+
2479
const result = React.useMemo(() => {
2580
if (!shareParam) {
2681
return { error: "Invalid share link: Missing parameters" };
@@ -69,7 +124,9 @@ export function SharePage() {
69124
return (
70125
<div className="flex flex-col items-center justify-center h-screen bg-slate-50 dark:bg-slate-900 text-slate-800 dark:text-white p-4">
71126
<AlertCircle className="w-12 h-12 text-red-500 mb-4" />
72-
<h1 className="text-xl font-bold mb-2">Error</h1>
127+
<h1 className="text-xl font-bold mb-2">
128+
{t(language, "share_error_title")}
129+
</h1>
73130
<p className="text-slate-500 dark:text-slate-400">{result.error}</p>
74131
</div>
75132
);
@@ -93,20 +150,24 @@ export function SharePage() {
93150
<h2 className="text-2xl font-bold text-slate-900 dark:text-white mb-2 break-all">
94151
{result.fileInfo.fileName}
95152
</h2>
96-
<p className="text-slate-500 dark:text-slate-400 mb-8">Shared File</p>
153+
<p className="text-slate-500 dark:text-slate-400 mb-8">
154+
{t(language, "share_file_label")}
155+
</p>
97156

98157
<a
99158
href={result.fileInfo.downloadUrl}
100159
className="block w-full py-4 bg-telegram-500 hover:bg-telegram-600 text-white rounded-xl font-bold text-lg shadow-lg shadow-telegram-500/20 transition-all transform hover:-translate-y-1 active:translate-y-0"
101160
>
102161
<div className="flex items-center justify-center gap-2">
103162
<Download className="w-6 h-6" />
104-
Download
163+
{t(language, "share_download_button")}
105164
</div>
106165
</a>
107166

108167
<div className="mt-8 pt-6 border-t border-slate-100 dark:border-slate-700">
109-
<p className="text-xs text-slate-400">Hosted via TeleCloud</p>
168+
<p className="text-xs text-slate-400">
169+
{t(language, "share_footer_hostedVia")}
170+
</p>
110171
</div>
111172
</div>
112173
</div>

constants.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import ReactHtmlParser from "html-react-parser";
33

44
export const TELEGRAM_API_BASE = "https://api.telegram.org";
55

6+
export const CONFIG_STORAGE_KEY = "telecloud_config";
7+
export const THEME_STORAGE_KEY = "telecloud_theme";
8+
69
export const CHUNK_SIZE = 20 * 1024 * 1024; // 20mb
710

811
export const formatBytes = (bytes: number, decimals = 2) => {
@@ -180,6 +183,18 @@ export const translations = {
180183
filter_time_custom: "Custom Range",
181184
filter_custom_from: "From",
182185
filter_custom_to: "To",
186+
share_error_title: "Error",
187+
share_error_missingParams: "Invalid share link: Missing parameters",
188+
share_error_malformedData: "Invalid share link: Malformed data",
189+
share_loading: "Loading shared file…",
190+
share_file_label: "Shared File",
191+
share_download_button: "Download",
192+
share_footer_hostedVia: "Hosted via TeleCloud",
193+
share_error_generic: "Something went wrong",
194+
share_error_expired: "This share link has expired",
195+
share_error_notFound: "File not found",
196+
share_error_permissionDenied:
197+
"You do not have permission to access this file",
183198
},
184199
zh: {
185200
app_title: "TeleCloud",
@@ -315,6 +330,17 @@ export const translations = {
315330
filter_time_custom: "自定义范围",
316331
filter_custom_from: "从",
317332
filter_custom_to: "到",
333+
share_error_title: "错误",
334+
share_error_missingParams: "无效的分享链接:缺少参数",
335+
share_error_malformedData: "无效的分享链接:数据格式错误",
336+
share_loading: "正在加载分享文件…",
337+
share_file_label: "已分享的文件",
338+
share_download_button: "下载",
339+
share_footer_hostedVia: "由 TeleCloud 提供",
340+
share_error_generic: "发生未知错误",
341+
share_error_expired: "该分享链接已失效",
342+
share_error_notFound: "文件不存在",
343+
share_error_permissionDenied: "你没有权限访问该文件",
318344
},
319345
};
320346

0 commit comments

Comments
 (0)