Skip to content

Commit

Permalink
feat: Add additional translations and improve favicon update logic (#308
Browse files Browse the repository at this point in the history
)
  • Loading branch information
Sittymin authored Jan 27, 2025
1 parent 5c2d000 commit edbcac5
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 58 deletions.
6 changes: 5 additions & 1 deletion client/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@
},
"favicon": {
"desc": "Set the icon (Favicon) displayed in the browser's address bar",
"title": "Favicon"
"title": "Favicon",
"update": {
"success": "Favicon update was successful",
"failed$message": "Favicon update failed, {{message}}"
}
},
"footer": {
"desc": "Set the footer content of the site (HTML)",
Expand Down
6 changes: 5 additions & 1 deletion client/public/locales/ja/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@
},
"favicon": {
"desc": "ブラウザのアドレスバーに表示されるアイコン(ファビコン)を設定します。",
"title": "ファビコン"
"title": "ファビコン",
"update": {
"success": "ファビコンの更新が成功しました",
"failed$message": "ファビコンの更新に失敗しました、{{message}}"
}
},
"footer": {
"desc": "サイトのフッターコンテンツを設定する(HTML)",
Expand Down
6 changes: 5 additions & 1 deletion client/public/locales/zh-CN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@
},
"favicon": {
"desc": "设置显示于浏览器的地址栏的图标(Favicon)",
"title": "网站图标"
"title": "网站图标",
"update": {
"success": "网站图标更新成功",
"failed$message": "网站图标更新失败,{{message}}"
}
},
"footer": {
"desc": "设置显示于站点底部的内容(HTML)",
Expand Down
6 changes: 5 additions & 1 deletion client/public/locales/zh-TW/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@
},
"favicon": {
"desc": "設定顯示於瀏覽器的地址欄的圖標(Favicon)",
"title": "網站圖標"
"title": "網站圖標",
"update": {
"success": "網站圖標更新成功",
"failed$message": "網站圖標更新失敗,{{message}}"
}
},
"footer": {
"desc": "設定顯示於網站底部的内容(HTML)",
Expand Down
4 changes: 2 additions & 2 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useRef, useState } from 'react'
import { useEffect, useRef, useState } from 'react'
import { Helmet } from 'react-helmet'
import { getCookie } from 'typescript-cookie'
import { DefaultParams, PathPattern, Route, Switch } from 'wouter'
Expand Down Expand Up @@ -61,7 +61,7 @@ function App() {
}
ref.current = true
}, [])
const favicon = useMemo(() => config.get<string>("favicon"), [config])
const favicon = `${process.env.API_URL}/favicon`;
return (
<>
<ClientConfigContext.Provider value={config}>
Expand Down
108 changes: 93 additions & 15 deletions client/src/page/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,46 @@ export function Settings() {
ref.current = true;
}, []);

function onFileChange(e: ChangeEvent<HTMLInputElement>) {
async function handleFaviconChange(e: ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0];
if (file) {
client.wp.post({
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
if (file.size > MAX_FILE_SIZE) {
showAlert(
t("upload.failed$size", {
size: MAX_FILE_SIZE / 1024 / 1024,
}),
);
return;
}
await client.favicon
.post(
{
file: file,
},
{
headers: headersWithAuth(),
},
)
.then(({ data }) => {
if (data && typeof data !== "string") {
showAlert(t("settings.favicon.update.success"));
}
})
.catch((err) => {
showAlert(
t("settings.favicon.update.failed$message", {
message: err.message,
}),
);
});
}
}

async function onFileChange(e: ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0];
if (file) {
await client.wp.post({
data: file,
}, {
headers: headersWithAuth()
Expand Down Expand Up @@ -106,7 +142,13 @@ export function Settings() {
<ItemSwitch title={t('settings.comment.enable.title')} description={t('settings.comment.enable.desc')} type="client" configKey="comment.enabled" />
<ItemSwitch title={t('settings.counter.enable.title')} description={t('settings.counter.enable.desc')} type="client" configKey="counter.enabled" />
<ItemSwitch title={t('settings.rss.title')} description={t('settings.rss.desc')} type="client" configKey="rss" />
<ItemInput title={t('settings.favicon.title')} description={t('settings.favicon.desc')} type="client" configKey="favicon" configKeyTitle="Favicon" />
<ItemWithUpload
title={t("settings.favicon.title")}
description={t("settings.favicon.desc")}
// @see https://developers.cloudflare.com/images/transform-images/#supported-input-formats
accept="image/jpeg,image/png,image/gif,image/webp,image/svg+xml"
onFileChange={handleFaviconChange}
/>
<ItemInput title={t('settings.footer.title')} description={t('settings.footer.desc')} type="client" configKey="footer" configKeyTitle="Footer HTML" />
<ItemButton title={t('settings.cache.clear.title')} description={t('settings.cache.clear.desc')} buttonTitle={t('clear')} onConfirm={async () => {
await client.config.cache.delete(undefined, {
Expand All @@ -119,6 +161,7 @@ export function Settings() {
})
}} alertTitle={t('settings.cache.clear.confirm.title')} alertDescription={t('settings.cache.clear.confirm.desc')} />
<ItemWithUpload title={t('settings.wordpress.title')} description={t('settings.wordpress.desc')}
accept="application/xml"
onFileChange={onFileChange} />
</div>
</main>
Expand Down Expand Up @@ -406,25 +449,60 @@ function ItemButton({
);
}

function ItemWithUpload({ title, description, onFileChange }: { title: string, description: string, onFileChange: (e: ChangeEvent<HTMLInputElement>) => void }) {
function ItemWithUpload({
title,
description,
accept,
onFileChange,
}: {
title: string;
description: string;
onFileChange: (e: ChangeEvent<HTMLInputElement>) => Promise<void>;
accept: string;
}) {
const inputRef = useRef<HTMLInputElement>(null);
const [loading, setLoading] = useState(false);
const { t } = useTranslation();

const handleFileChange = async (e: ChangeEvent<HTMLInputElement>) => {
setLoading(true);
try {
await onFileChange(e);
} finally {
setLoading(false);
}
};

return (
<div className="flex flex-col w-full items-start">
<div className="flex flex-row justify-between w-full items-center">
<div className="flex flex-col">
<p className="text-lg font-bold dark:text-white">
{title}
</p>
<p className="text-xs text-neutral-500">
{description}
</p>
<p className="text-lg font-bold dark:text-white">{title}</p>
<p className="text-xs text-neutral-500">{description}</p>
</div>
<div className="flex flex-row items-center justify-center space-x-4">
{loading && (
<ReactLoading
width="1em"
height="1em"
type="spin"
color="#FC466B"
/>
)}
<input
ref={inputRef}
type="file"
className="hidden"
accept={accept}
onChange={handleFileChange}
/>
<Button
onClick={() => {
inputRef.current?.click();
}}
title={t("upload.title")}
/>
</div>
<input ref={inputRef} type="file" className="hidden" accept="application/xml"
onChange={onFileChange} />
<Button onClick={() => {
inputRef.current?.click();
}} title={t('upload.title')} />
</div>
</div>
);
Expand Down
2 changes: 0 additions & 2 deletions client/src/state/config.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { createContext } from "react";

const defaultFavicon = process.env.AVATAR ? `//wsrv.nl/?url=${encodeURIComponent(process.env.AVATAR)}&w=144&h=144&mask=circle` : '/favicon.ico';
export const defaultClientConfig = new Map(Object.entries({
"favicon": defaultFavicon,
"counter.enabled": true,
"friend_apply_enable": true,
"comment.enabled": true,
Expand Down
4 changes: 3 additions & 1 deletion server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import cors from '@elysiajs/cors';
import { serverTiming } from '@elysiajs/server-timing';
import { Elysia } from 'elysia';
import { CommentService } from './services/comments';
import { FaviconService } from "./services/favicon";
import { FeedService } from './services/feed';
import { FriendService } from './services/friends';
import { RSSService } from './services/rss';
Expand All @@ -28,6 +29,7 @@ export const app = () => new Elysia({ aot: false })
enabled: true,
}))
.use(UserService())
.use(FaviconService())
.use(FeedService())
.use(CommentService())
.use(TagService())
Expand All @@ -42,4 +44,4 @@ export const app = () => new Elysia({ aot: false })
return `${path} ${JSON.stringify(params)} not found`
})

export type App = ReturnType<typeof app>;
export type App = ReturnType<typeof app>;
Loading

0 comments on commit edbcac5

Please sign in to comment.