Improve publish page.

This commit is contained in:
2025-05-15 19:53:30 +08:00
parent 75389bc3c0
commit f8271161cb
3 changed files with 57 additions and 41 deletions

View File

@@ -19,7 +19,7 @@ export const i18nData = {
"Don't have an account? Register": "Don't have an account? Register", "Don't have an account? Register": "Don't have an account? Register",
"Already have an account? Login": "Already have an account? Login", "Already have an account? Login": "Already have an account? Login",
"Publish Resource": "Publish Resource", "Publish Resource": "Publish Resource",
"All information, images, and files can be modified after publishing": "All information, images, and files can be modified after publishing", "All information can be modified after publishing": "All information can be modified after publishing",
"Title": "Title", "Title": "Title",
"Alternative Titles": "Alternative Titles", "Alternative Titles": "Alternative Titles",
"Add Alternative Title": "Add Alternative Title", "Add Alternative Title": "Add Alternative Title",
@@ -41,14 +41,14 @@ export const i18nData = {
"Enter a search keyword to continue": "Enter a search keyword to continue", "Enter a search keyword to continue": "Enter a search keyword to continue",
"My Info": "My Info", "My Info": "My Info",
"Server": "Server", "Server": "Server",
// Management page translations // Management page translations
"Manage": "Manage", "Manage": "Manage",
"Storage": "Storage", "Storage": "Storage",
"Users": "Users", "Users": "Users",
"You are not logged in. Please log in to access this page.": "You are not logged in. Please log in to access this page.", "You are not logged in. Please log in to access this page.": "You are not logged in. Please log in to access this page.",
"You are not authorized to access this page.": "You are not authorized to access this page.", "You are not authorized to access this page.": "You are not authorized to access this page.",
// Storage management // Storage management
"No storage found. Please create a new storage.": "No storage found. Please create a new storage.", "No storage found. Please create a new storage.": "No storage found. Please create a new storage.",
"Name": "Name", "Name": "Name",
@@ -72,7 +72,7 @@ export const i18nData = {
"Storage created successfully": "Storage created successfully", "Storage created successfully": "Storage created successfully",
"Close": "Close", "Close": "Close",
"Submit": "Submit", "Submit": "Submit",
// User management // User management
"Admin": "Admin", "Admin": "Admin",
"Can Upload": "Can Upload", "Can Upload": "Can Upload",
@@ -109,28 +109,28 @@ export const i18nData = {
"Upload a file to server, then the file will be moved to the selected storage.": "Upload a file to server, then the file will be moved to the selected storage.", "Upload a file to server, then the file will be moved to the selected storage.": "Upload a file to server, then the file will be moved to the selected storage.",
"Select Storage": "Select Storage", "Select Storage": "Select Storage",
"Resource Details": "Resource Details", "Resource Details": "Resource Details",
"Delete Resource": "Delete Resource", "Delete Resource": "Delete Resource",
"Are you sure you want to delete the resource": "Are you sure you want to delete the resource", "Are you sure you want to delete the resource": "Are you sure you want to delete the resource",
"Delete File": "Delete File", "Delete File": "Delete File",
"Are you sure you want to delete the file": "Are you sure you want to delete the file", "Are you sure you want to delete the file": "Are you sure you want to delete the file",
// New translations // New translations
"Change Avatar": "Change Avatar", "Change Avatar": "Change Avatar",
"Change Username": "Change Username", "Change Username": "Change Username",
"Change Password": "Change Password", "Change Password": "Change Password",
"New Username": "New Username", "New Username": "New Username",
"Enter new username": "Enter new username", "Enter new username": "Enter new username",
"Save": "Save", "Save": "Save",
"Current Password": "Current Password", "Current Password": "Current Password",
"Enter current password": "Enter current password", "Enter current password": "Enter current password",
"New Password": "New Password", "New Password": "New Password",
"Enter new password": "Enter new password", "Enter new password": "Enter new password",
"Confirm New Password": "Confirm New Password", "Confirm New Password": "Confirm New Password",
"Confirm new password": "Confirm new password", "Confirm new password": "Confirm new password",
"Avatar changed successfully": "Avatar changed successfully", "Avatar changed successfully": "Avatar changed successfully",
"Username changed successfully": "Username changed successfully", "Username changed successfully": "Username changed successfully",
"Password changed successfully": "Password changed successfully", "Password changed successfully": "Password changed successfully",
// Manage server config page translations // Manage server config page translations
"Update server config successfully": "Update server config successfully", "Update server config successfully": "Update server config successfully",
"Max uploading size (MB)": "Max uploading size (MB)", "Max uploading size (MB)": "Max uploading size (MB)",
@@ -138,10 +138,15 @@ export const i18nData = {
"Max downloads per day for single IP": "Max downloads per day for single IP", "Max downloads per day for single IP": "Max downloads per day for single IP",
"Allow register": "Allow register", "Allow register": "Allow register",
"Server name": "Server name", "Server name": "Server name",
"Server description": "Server description", "Server description": "Server description",
"Cloudflare Turnstile Site Key": "Cloudflare Turnstile Site Key", "Cloudflare Turnstile Site Key": "Cloudflare Turnstile Site Key",
"Cloudflare Turnstile Secret Key": "Cloudflare Turnstile Secret Key", "Cloudflare Turnstile Secret Key": "Cloudflare Turnstile Secret Key",
"If the cloudflare turnstile keys are not empty, the turnstile will be used for register and download.": "If the cloudflare turnstile keys are not empty, the turnstile will be used for register and download.", "If the cloudflare turnstile keys are not empty, the turnstile will be used for register and download.": "If the cloudflare turnstile keys are not empty, the turnstile will be used for register and download.",
"The first image will be used as the cover image": "The first image will be used as the cover image",
"Please enter a search keyword": "Please enter a search keyword",
"Searching...": "Searching...",
"Create Tag": "Create Tag",
"Search Tags": "Search Tags",
} }
}, },
"zh-CN": { "zh-CN": {
@@ -164,7 +169,7 @@ export const i18nData = {
"Don't have an account? Register": "没有账号?注册", "Don't have an account? Register": "没有账号?注册",
"Already have an account? Login": "已有账号?登录", "Already have an account? Login": "已有账号?登录",
"Publish Resource": "发布资源", "Publish Resource": "发布资源",
"All information, images, and files can be modified after publishing": "所有的信息, 图片, 文件均可在发布后修改", "All information can be modified after publishing": "所有的信息均可在发布后修改",
"Title": "标题", "Title": "标题",
"Alternative Titles": "其他标题", "Alternative Titles": "其他标题",
"Add Alternative Title": "新增标题", "Add Alternative Title": "新增标题",
@@ -267,15 +272,15 @@ export const i18nData = {
"Enter new username": "输入新用户名", "Enter new username": "输入新用户名",
"Save": "保存", "Save": "保存",
"Current Password": "当前密码", "Current Password": "当前密码",
"Enter current password": "输入当前密码", "Enter current password": "输入当前密码",
"New Password": "新密码", "New Password": "新密码",
"Enter new password": "输入新密码", "Enter new password": "输入新密码",
"Confirm New Password": "确认新密码", "Confirm New Password": "确认新密码",
"Confirm new password": "确认新密码", "Confirm new password": "确认新密码",
"Avatar changed successfully": "头像更改成功", "Avatar changed successfully": "头像更改成功",
"Username changed successfully": "用户名更改成功", "Username changed successfully": "用户名更改成功",
"Password changed successfully": "密码更改成功", "Password changed successfully": "密码更改成功",
// Manage server config page translations // Manage server config page translations
"Update server config successfully": "成功更新服务器配置", "Update server config successfully": "成功更新服务器配置",
"Max uploading size (MB)": "最大上传大小 (MB)", "Max uploading size (MB)": "最大上传大小 (MB)",
@@ -287,6 +292,11 @@ export const i18nData = {
"Cloudflare Turnstile Site Key": "Cloudflare Turnstile 站点密钥", "Cloudflare Turnstile Site Key": "Cloudflare Turnstile 站点密钥",
"Cloudflare Turnstile Secret Key": "Cloudflare Turnstile 密钥", "Cloudflare Turnstile Secret Key": "Cloudflare Turnstile 密钥",
"If the cloudflare turnstile keys are not empty, the turnstile will be used for register and download.": "如果设置了 Cloudflare Turnstile 密钥,将在注册和下载时启用验证", "If the cloudflare turnstile keys are not empty, the turnstile will be used for register and download.": "如果设置了 Cloudflare Turnstile 密钥,将在注册和下载时启用验证",
"The first image will be used as the cover image": "第一张图片将用作封面图片",
"Please enter a search keyword": "请输入搜索关键词",
"Searching...": "搜索中...",
"Create Tag": "创建标签",
"Search Tags": "搜索标签",
} }
}, },
"zh-TW": { "zh-TW": {
@@ -309,7 +319,7 @@ export const i18nData = {
"Don't have an account? Register": "沒有賬號?註冊", "Don't have an account? Register": "沒有賬號?註冊",
"Already have an account? Login": "已有賬號?登入", "Already have an account? Login": "已有賬號?登入",
"Publish Resource": "發布資源", "Publish Resource": "發布資源",
"All information, images, and files can be modified after publishing": "所有資訊、圖片、檔案均可於發布後修改", "All information can be modified after publishing": "所有資訊均可於發布後修改",
"Title": "標題", "Title": "標題",
"Alternative Titles": "其他標題", "Alternative Titles": "其他標題",
"Add Alternative Title": "新增標題", "Add Alternative Title": "新增標題",
@@ -401,7 +411,7 @@ export const i18nData = {
"Resource Details": "資源詳情", "Resource Details": "資源詳情",
"Delete Resource": "刪除資源", "Delete Resource": "刪除資源",
"Are you sure you want to delete the resource": "您確定要刪除此資源嗎", "Are you sure you want to delete the resource": "您確定要刪除此資源嗎",
"Delete File": "刪除檔案", "Delete File": "刪除檔案",
"Are you sure you want to delete the file": "您確定要刪除此檔案嗎", "Are you sure you want to delete the file": "您確定要刪除此檔案嗎",
// New translations // New translations
@@ -414,13 +424,13 @@ export const i18nData = {
"Current Password": "當前密碼", "Current Password": "當前密碼",
"Enter current password": "輸入當前密碼", "Enter current password": "輸入當前密碼",
"New Password": "新密碼", "New Password": "新密碼",
"Enter new password": "輸入新密碼", "Enter new password": "輸入新密碼",
"Confirm New Password": "確認新密碼", "Confirm New Password": "確認新密碼",
"Confirm new password": "確認新密碼", "Confirm new password": "確認新密碼",
"Avatar changed successfully": "頭像更改成功", "Avatar changed successfully": "頭像更改成功",
"Username changed successfully": "用戶名更改成功", "Username changed successfully": "用戶名更改成功",
"Password changed successfully": "密碼更改成功", "Password changed successfully": "密碼更改成功",
// Manage server config page translations // Manage server config page translations
"Update server config successfully": "成功更新伺服器配置", "Update server config successfully": "成功更新伺服器配置",
"Max uploading size (MB)": "最大上傳大小 (MB)", "Max uploading size (MB)": "最大上傳大小 (MB)",
@@ -432,6 +442,11 @@ export const i18nData = {
"Cloudflare Turnstile Site Key": "Cloudflare Turnstile 網站密鑰", "Cloudflare Turnstile Site Key": "Cloudflare Turnstile 網站密鑰",
"Cloudflare Turnstile Secret Key": "Cloudflare Turnstile 密鑰", "Cloudflare Turnstile Secret Key": "Cloudflare Turnstile 密鑰",
"If the cloudflare turnstile keys are not empty, the turnstile will be used for register and download.": "如果設置了 Cloudflare Turnstile 密鑰,將在註冊和下載時啟用驗證", "If the cloudflare turnstile keys are not empty, the turnstile will be used for register and download.": "如果設置了 Cloudflare Turnstile 密鑰,將在註冊和下載時啟用驗證",
"The first image will be used as the cover image": "第一張圖片將用作封面圖片",
"Please enter a search keyword": "請輸入搜尋關鍵字",
"Searching...": "搜尋中...",
"Create Tag": "創建標籤",
"Search Tags": "搜尋標籤",
} }
} }
} }

View File

@@ -7,18 +7,18 @@
prefersdark: false; prefersdark: false;
color-scheme: "light"; color-scheme: "light";
--color-base-100: oklch(99% 0.014 343.198); --color-base-100: oklch(99% 0.014 343.198);
--color-base-200: oklch(96% 0.028 342.258); --color-base-200: oklch(97% 0.028 342.258);
--color-base-300: oklch(84% 0.061 343.231); --color-base-300: oklch(84% 0.061 343.231);
--color-base-content: oklch(0% 0 0); --color-base-content: oklch(0% 0 0);
--color-primary: oklch(65% 0.241 354.308); --color-primary: oklch(65% 0.241 354.308);
--color-primary-content: oklch(100% 0 0); --color-primary-content: oklch(100% 0 0);
--color-secondary: oklch(62% 0.265 303.9); --color-secondary: oklch(62% 0.265 303.9);
--color-secondary-content: oklch(97% 0.014 308.299); --color-secondary-content: oklch(97% 0.014 308.299);
--color-accent: oklch(78% 0.115 274.713); --color-accent: oklch(0.759 0.124 274.458);
--color-accent-content: oklch(39% 0.09 240.876); --color-accent-content: oklch(20% 0.09 240.876);
--color-neutral: oklch(40% 0.153 2.432); --color-neutral: oklch(40% 0.153 2.432);
--color-neutral-content: oklch(89% 0.061 343.231); --color-neutral-content: oklch(89% 0.061 343.231);
--color-info: oklch(80% 0.105 251.813); --color-info: oklch(75% 0.105 251.813);
--color-info-content: oklch(44% 0.11 240.79); --color-info-content: oklch(44% 0.11 240.79);
--color-success: oklch(70% 0.14 182.503); --color-success: oklch(70% 0.14 182.503);
--color-success-content: oklch(43% 0.095 166.913); --color-success-content: oklch(43% 0.095 166.913);
@@ -27,7 +27,7 @@
--color-error: oklch(63% 0.237 25.331); --color-error: oklch(63% 0.237 25.331);
--color-error-content: oklch(97% 0.013 17.38); --color-error-content: oklch(97% 0.013 17.38);
--radius-selector: 1rem; --radius-selector: 1rem;
--radius-field: 1rem; --radius-field: 1.5rem;
--radius-box: 1rem; --radius-box: 1rem;
--size-selector: 0.25rem; --size-selector: 0.25rem;
--size-field: 0.25rem; --size-field: 0.25rem;
@@ -62,7 +62,7 @@
--color-error: oklch(68.22% 0.206 24.43); --color-error: oklch(68.22% 0.206 24.43);
--color-error-content: oklch(13.644% 0.041 24.43); --color-error-content: oklch(13.644% 0.041 24.43);
--radius-selector: 1rem; --radius-selector: 1rem;
--radius-field: 1rem; --radius-field: 1.5rem;
--radius-box: 1rem; --radius-box: 1rem;
--size-selector: 0.25rem; --size-selector: 0.25rem;
--size-field: 0.25rem; --size-field: 0.25rem;

View File

@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { MdAdd, MdDelete, MdOutlineInfo } from "react-icons/md"; import {MdAdd, MdClose, MdDelete, MdOutlineInfo, MdSearch} from "react-icons/md";
import { Tag } from "../network/models.ts"; import { Tag } from "../network/models.ts";
import { network } from "../network/network.ts"; import { network } from "../network/network.ts";
import { LuInfo } from "react-icons/lu"; import { LuInfo } from "react-icons/lu";
@@ -24,7 +24,7 @@ export default function PublishPage() {
useEffect(() => { useEffect(() => {
document.title = t("Publish Resource"); document.title = t("Publish Resource");
}, []) }, [t])
const handleSubmit = async () => { const handleSubmit = async () => {
if (isSubmitting) { if (isSubmitting) {
@@ -102,7 +102,7 @@ export default function PublishPage() {
<h1 className={"text-2xl font-bold my-4"}>{t("Publish Resource")}</h1> <h1 className={"text-2xl font-bold my-4"}>{t("Publish Resource")}</h1>
<div role="alert" className="alert alert-info mb-2 alert-dash"> <div role="alert" className="alert alert-info mb-2 alert-dash">
<MdOutlineInfo size={24} /> <MdOutlineInfo size={24} />
<span>{t("All information, images, and files can be modified after publishing")}</span> <span>{t("All information can be modified after publishing")}</span>
</div> </div>
<p className={"my-1"}>{t("Title")}</p> <p className={"my-1"}>{t("Title")}</p>
<input type="text" className="input w-full" value={title} onChange={(e) => setTitle(e.target.value)} /> <input type="text" className="input w-full" value={title} onChange={(e) => setTitle(e.target.value)} />
@@ -137,7 +137,16 @@ export default function PublishPage() {
<p className={"my-1 pb-1"}> <p className={"my-1 pb-1"}>
{ {
tags.map((tag, index) => { tags.map((tag, index) => {
return <span key={index} className={"badge badge-primary mr-2"}>{tag.name}</span> return <span key={index} className={"badge badge-primary mr-2 text-sm"}>
{tag.name}
<span onClick={() => {
const newTags = [...tags]
newTags.splice(index, 1)
setTags(newTags)
}}>
<MdClose size={18}/>
</span>
</span>
}) })
} }
</p> </p>
@@ -155,7 +164,10 @@ export default function PublishPage() {
<p className={"my-1"}>{t("Images")}</p> <p className={"my-1"}>{t("Images")}</p>
<div role="alert" className="alert alert-info alert-soft my-2"> <div role="alert" className="alert alert-info alert-soft my-2">
<MdOutlineInfo size={24} /> <MdOutlineInfo size={24} />
<span>{t("Images will not be displayed automatically, you need to reference them in the description")}</span> <div>
<p>{t("Images will not be displayed automatically, you need to reference them in the description")}</p>
<p>{t("The first image will be used as the cover image")}</p>
</div>
</div> </div>
<div className={`rounded-box border border-base-content/5 bg-base-100 ${images.length === 0 ? "hidden" : ""}`}> <div className={`rounded-box border border-base-content/5 bg-base-100 ${images.length === 0 ? "hidden" : ""}`}>
<table className={"table"}> <table className={"table"}>
@@ -273,7 +285,7 @@ function TagInput({ onAdd }: { onAdd: (tag: Tag) => void }) {
input.blur() input.blur()
} }
let dropdownContent = <></> let dropdownContent
if (error) { if (error) {
dropdownContent = <div className="alert alert-error my-2"> dropdownContent = <div className="alert alert-error my-2">
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 shrink-0 stroke-current" fill="none" <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 shrink-0 stroke-current" fill="none"
@@ -319,18 +331,7 @@ function TagInput({ onAdd }: { onAdd: (tag: Tag) => void }) {
return <div className={"dropdown dropdown-end"}> return <div className={"dropdown dropdown-end"}>
<label className="input"> <label className="input">
<svg className="h-[1em] opacity-50" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <MdSearch size={18}/>
<g
stroke-linejoin="round"
stroke-linecap="round"
stroke-width="2.5"
fill="none"
stroke="currentColor"
>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</g>
</svg>
<input autoComplete={"off"} id={"search_tags_input"} tabIndex={0} type="text" className="grow" placeholder={t("Search Tags")} value={keyword} onChange={(e) => handleChange(e.target.value)} /> <input autoComplete={"off"} id={"search_tags_input"} tabIndex={0} type="text" className="grow" placeholder={t("Search Tags")} value={keyword} onChange={(e) => handleChange(e.target.value)} />
</label> </label>
<ul tabIndex={0} className="dropdown-content menu bg-base-100 rounded-box z-1 w-52 p-2 shadow mt-2 border border-base-300"> <ul tabIndex={0} className="dropdown-content menu bg-base-100 rounded-box z-1 w-52 p-2 shadow mt-2 border border-base-300">