mirror of
https://github.com/cloudreve/frontend.git
synced 2025-12-25 19:52:48 +00:00
feat(share): improve UI for share link result (follow up #https://github.com/cloudreve/frontend/pull/259)
This commit is contained in:
parent
00f18b18ec
commit
ededea6c45
|
|
@ -307,7 +307,6 @@
|
|||
"createShareLink": "Share",
|
||||
"viewDetails": "View details",
|
||||
"copy": "Copy",
|
||||
"copyLinkAlongWithPassword": "Copy link and password",
|
||||
"bytes": " ({{bytes}} Bytes)",
|
||||
"storagePolicy": "Storage policy",
|
||||
"childFolders": "Child folders",
|
||||
|
|
@ -371,6 +370,8 @@
|
|||
"deleteViewSetting": "Delete view setting"
|
||||
},
|
||||
"modals": {
|
||||
"includePasswordInShareLink": "Include password in share link",
|
||||
"includePasswordInShareLinkDes": "If selected, password will be included in the share link, and no password is required when accessing the share link.",
|
||||
"showFileName": "Show file name",
|
||||
"archiveFile": "Archive file",
|
||||
"cancelDownload": "Cancel download",
|
||||
|
|
@ -468,10 +469,9 @@
|
|||
"shareLinkShareContent": "I shared with you: {{name}} Link: {{link}}",
|
||||
"shareLinkPasswordInfo": "Password: {{password}}",
|
||||
"createShareLink": "Create share link",
|
||||
"privateShare": "Hide from public",
|
||||
"privateShareDes": "If selected, other people cannot see this share link on your homepage.",
|
||||
"privateShare": "Protect with password",
|
||||
"privateShareDes": "If selected, password is required to access the share link, others cannot see this share link on your homepage.",
|
||||
"useCustomPassword": "Custom share link password",
|
||||
"passwordAutoGenerate": "Auto generate",
|
||||
"shareView": "Share view setting",
|
||||
"shareViewDes": "If selected, other users can see your view setting (layout, sorting, etc.) saved on the server server when accessing this shared folder.",
|
||||
"expireAfterDownload": "Expire after being downloaded",
|
||||
|
|
|
|||
|
|
@ -308,7 +308,6 @@
|
|||
"createShareLink": "共有リンクの作成",
|
||||
"viewDetails": "詳細情報",
|
||||
"copy": "コピー",
|
||||
"copyLinkAlongWithPassword": "パスワード付きリンクをコピー",
|
||||
"bytes": " ({{bytes}} バイト)",
|
||||
"storagePolicy": "ストレージポリシー",
|
||||
"childFolders": "ディレクトリの内容",
|
||||
|
|
@ -372,6 +371,8 @@
|
|||
"deleteViewSetting": "ビュー設定を削除"
|
||||
},
|
||||
"modals": {
|
||||
"includePasswordInShareLink": "共有リンクにパスワードを含める",
|
||||
"includePasswordInShareLinkDes": "チェックを入れると、共有リンクにパスワードが含まれます。このリンクにアクセスする際には、パスワードを入力する必要はありません。",
|
||||
"showFileName": "ファイル名を表示",
|
||||
"archiveFile": "圧縮ファイル",
|
||||
"cancelDownload": "ダウンロードキャンセル",
|
||||
|
|
@ -469,8 +470,8 @@
|
|||
"shareLinkShareContent": "{{name}} を共有しました。リンク:{{link}}",
|
||||
"shareLinkPasswordInfo": "パスワード:{{password}}",
|
||||
"createShareLink": "共有リンク作成",
|
||||
"privateShare": "共有を非表示",
|
||||
"privateShareDes": "チェックを入れると他の人はあなたのプロフィールページでこの共有リンクを見ることができません。",
|
||||
"privateShare": "パスワードで保護",
|
||||
"privateShareDes": "チェックを入れると、パスワードが必要です。他の人はあなたのプロフィールページでこの共有リンクを見ることができません。",
|
||||
"useCustomPassword": "カスタムパスワードを使用",
|
||||
"expireAfterDownload": "ダウンロード後に自動的に期限切れ",
|
||||
"sharePassword": "共有パスワード",
|
||||
|
|
|
|||
|
|
@ -307,7 +307,6 @@
|
|||
"createShareLink": "创建分享链接",
|
||||
"viewDetails": "详细信息",
|
||||
"copy": "复制",
|
||||
"copyLinkAlongWithPassword": "复制链接和密码",
|
||||
"bytes": " ({{bytes}} 字节)",
|
||||
"storagePolicy": "存储策略",
|
||||
"childFolders": "包含目录",
|
||||
|
|
@ -371,6 +370,8 @@
|
|||
"deleteViewSetting": "删除视图设置"
|
||||
},
|
||||
"modals": {
|
||||
"includePasswordInShareLink": "在链接中包含密码",
|
||||
"includePasswordInShareLinkDes": "勾选后,分享链接中会包含密码,通过此链接访问时不需要再输入密码。",
|
||||
"showFileName": "显示文件名",
|
||||
"archiveFile": "压缩文件",
|
||||
"cancelDownload": "取消下载",
|
||||
|
|
@ -468,8 +469,8 @@
|
|||
"shareLinkShareContent": "我向你分享了:{{name}} 链接:{{link}}",
|
||||
"shareLinkPasswordInfo": " 密码: {{password}}",
|
||||
"createShareLink": "创建分享链接",
|
||||
"privateShare": "隐藏分享",
|
||||
"privateShareDes": "勾选后,其他人无法在你的个人主页看到此分享链接。",
|
||||
"privateShare": "使用密码保护链接",
|
||||
"privateShareDes": "勾选后,需要使用密码访问分享链接,其他人无法在你的个人主页看到此分享链接。",
|
||||
"useCustomPassword": "自定义分享密码",
|
||||
"expireAfterDownload": "下载后自动过期",
|
||||
"sharePassword": "分享密码",
|
||||
|
|
|
|||
|
|
@ -307,7 +307,6 @@
|
|||
"createShareLink": "建立分享連結",
|
||||
"viewDetails": "詳細資訊",
|
||||
"copy": "復制",
|
||||
"copyLinkAlongWithPassword": "復制連結和密碼",
|
||||
"bytes": " ({{bytes}} 位元組)",
|
||||
"storagePolicy": "儲存策略",
|
||||
"childFolders": "包含目錄",
|
||||
|
|
@ -367,6 +366,8 @@
|
|||
"off": "關閉"
|
||||
},
|
||||
"modals": {
|
||||
"includePasswordInShareLink": "在連結中包含密碼",
|
||||
"includePasswordInShareLinkDes": "勾選後,分享連結中會包含密碼,通過此連結訪問時不需要再輸入密碼。",
|
||||
"showFileName": "顯示檔名",
|
||||
"archiveFile": "壓縮檔案",
|
||||
"cancelDownload": "取消下載",
|
||||
|
|
@ -464,8 +465,8 @@
|
|||
"shareLinkShareContent": "我向你分享了:{{name}} 連結:{{link}}",
|
||||
"shareLinkPasswordInfo": " 密碼: {{password}}",
|
||||
"createShareLink": "建立分享連結",
|
||||
"privateShare": "隱藏分享",
|
||||
"privateShareDes": "勾選後,其他人無法在你的個人主頁看到此分享連結。",
|
||||
"privateShare": "使用密碼保護連結",
|
||||
"privateShareDes": "勾選後,需要使用密碼訪問分享連結,其他人無法在你的個人主頁看到此分享連結。",
|
||||
"useCustomPassword": "使用自定義密碼",
|
||||
"expireAfterDownload": "下載後自動過期",
|
||||
"sharePassword": "分享密碼",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Box, DialogContent, IconButton, List, Tooltip, useTheme } from "@mui/material";
|
||||
import { Box, Checkbox, Collapse, DialogContent, IconButton, Stack, Tooltip, useTheme } from "@mui/material";
|
||||
import dayjs from "dayjs";
|
||||
import { TFunction } from "i18next";
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
|
|
@ -10,12 +10,12 @@ import { useAppDispatch, useAppSelector } from "../../../../redux/hooks.ts";
|
|||
import { createOrUpdateShareLink } from "../../../../redux/thunks/share.ts";
|
||||
import { copyToClipboard, sendLink } from "../../../../util";
|
||||
import AutoHeight from "../../../Common/AutoHeight.tsx";
|
||||
import { FilledTextField } from "../../../Common/StyledComponents.tsx";
|
||||
import { FilledTextField, SmallFormControlLabel } from "../../../Common/StyledComponents.tsx";
|
||||
import DraggableDialog from "../../../Dialogs/DraggableDialog.tsx";
|
||||
import CopyOutlined from "../../../Icons/CopyOutlined.tsx";
|
||||
import Share from "../../../Icons/Share.tsx";
|
||||
import { FileManagerIndex } from "../../FileManager.tsx";
|
||||
import ShareSettingContent, { downloadOptions, expireOptions, ShareSetting } from "./ShareSetting.tsx";
|
||||
import CopyOutlined from "../../../Icons/CopyOutlined.tsx";
|
||||
|
||||
const initialSetting: ShareSetting = {
|
||||
expires_val: expireOptions[2],
|
||||
|
|
@ -72,6 +72,7 @@ const ShareDialog = () => {
|
|||
const [loading, setLoading] = useState(false);
|
||||
const [setting, setSetting] = useState<ShareSetting>(initialSetting);
|
||||
const [shareLink, setShareLink] = useState<string>("");
|
||||
const [includePassword, setIncludePassword] = useState(true);
|
||||
const shareLinkPassword = useMemo(() => {
|
||||
const start = shareLink.lastIndexOf("/s/");
|
||||
const shareLinkParts = shareLink.substring(start + 3).split("/");
|
||||
|
|
@ -130,6 +131,20 @@ const ShareDialog = () => {
|
|||
[dispatch, target, shareLink, editTarget, setLoading, setting, setShareLink],
|
||||
);
|
||||
|
||||
const finalShareLink = useMemo(() => {
|
||||
if (includePassword) {
|
||||
return shareLink;
|
||||
}
|
||||
return shareLink.substring(0, shareLink.lastIndexOf("/"));
|
||||
}, [includePassword, shareLink]);
|
||||
|
||||
const finalShareLinkPassword = useMemo(() => {
|
||||
if (!includePassword) {
|
||||
return shareLink.substring(shareLink.lastIndexOf("/") + 1);
|
||||
}
|
||||
return undefined;
|
||||
}, [includePassword, shareLink]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<DraggableDialog
|
||||
|
|
@ -137,6 +152,7 @@ const ShareDialog = () => {
|
|||
showActions
|
||||
loading={loading}
|
||||
showCancel
|
||||
hideOk={!!shareLink}
|
||||
onAccept={onAccept}
|
||||
dialogProps={{
|
||||
open: open ?? false,
|
||||
|
|
@ -145,19 +161,12 @@ const ShareDialog = () => {
|
|||
maxWidth: "xs",
|
||||
}}
|
||||
cancelText={shareLink ? "common:close" : undefined}
|
||||
okText={
|
||||
shareLink
|
||||
? shareLinkPassword.password
|
||||
? "fileManager.copyLinkAlongWithPassword"
|
||||
: "fileManager.copy"
|
||||
: undefined
|
||||
}
|
||||
secondaryAction={
|
||||
shareLink
|
||||
? // @ts-ignore
|
||||
navigator.share && (
|
||||
<Tooltip title={t("application:modals.sendLink")}>
|
||||
<IconButton onClick={() => sendLink(target?.name ?? "", shareLink)}>
|
||||
<IconButton onClick={() => sendLink(target?.name ?? "", finalShareLink)}>
|
||||
<Share />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
|
@ -183,26 +192,19 @@ const ShareDialog = () => {
|
|||
/>
|
||||
)}
|
||||
{shareLink && (
|
||||
<List
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: theme.spacing(1),
|
||||
padding: theme.spacing(1),
|
||||
}}
|
||||
>
|
||||
<Stack spacing={1}>
|
||||
<FilledTextField
|
||||
variant={"filled"}
|
||||
inputProps={{ readonly: true }}
|
||||
label={t("modals.shareLink")}
|
||||
fullWidth
|
||||
value={shareLinkPassword.shareLink}
|
||||
value={finalShareLink ?? ""}
|
||||
onFocus={(e) => e.target.select()}
|
||||
slotProps={{
|
||||
input: {
|
||||
endAdornment: (
|
||||
<IconButton
|
||||
onClick={() => copyToClipboard(shareLink.substring(0, shareLink.lastIndexOf("/")))}
|
||||
onClick={() => copyToClipboard(finalShareLink)}
|
||||
size="small"
|
||||
sx={{ marginRight: -1 }}
|
||||
>
|
||||
|
|
@ -213,31 +215,54 @@ const ShareDialog = () => {
|
|||
}}
|
||||
/>
|
||||
{shareLinkPassword.password && (
|
||||
<FilledTextField
|
||||
variant={"filled"}
|
||||
inputProps={{ readonly: true }}
|
||||
label={t("modals.sharePassword")}
|
||||
fullWidth
|
||||
value={shareLinkPassword.password}
|
||||
onFocus={(e) => e.target.select()}
|
||||
slotProps={{
|
||||
input: {
|
||||
endAdornment: (
|
||||
<IconButton
|
||||
onClick={() =>
|
||||
copyToClipboard(shareLink.substring(shareLink.lastIndexOf("/") + 1) ?? "")
|
||||
}
|
||||
<>
|
||||
<Collapse in={!includePassword}>
|
||||
<FilledTextField
|
||||
variant={"filled"}
|
||||
inputProps={{ readonly: true }}
|
||||
label={t("modals.sharePassword")}
|
||||
fullWidth
|
||||
value={finalShareLinkPassword ?? ""}
|
||||
onFocus={(e) => e.target.select()}
|
||||
slotProps={{
|
||||
input: {
|
||||
endAdornment: (
|
||||
<IconButton
|
||||
onClick={() => copyToClipboard(finalShareLinkPassword ?? "")}
|
||||
size="small"
|
||||
sx={{ marginRight: -1 }}
|
||||
>
|
||||
<CopyOutlined />
|
||||
</IconButton>
|
||||
),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Collapse>
|
||||
<Tooltip enterDelay={100} title={t("application:modals.includePasswordInShareLinkDes")}>
|
||||
<SmallFormControlLabel
|
||||
sx={{
|
||||
mt: "0!important",
|
||||
}}
|
||||
control={
|
||||
<Checkbox
|
||||
disableRipple
|
||||
sx={{
|
||||
pl: 0,
|
||||
}}
|
||||
size="small"
|
||||
sx={{ marginRight: -1 }}
|
||||
>
|
||||
<CopyOutlined />
|
||||
</IconButton>
|
||||
),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
checked={includePassword}
|
||||
onChange={() => {
|
||||
setIncludePassword(!includePassword);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={t("application:modals.includePasswordInShareLink")}
|
||||
/>
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
</List>
|
||||
</Stack>
|
||||
)}
|
||||
</Box>
|
||||
</CSSTransition>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import {
|
||||
Autocomplete,
|
||||
Box,
|
||||
Checkbox,
|
||||
Collapse,
|
||||
createFilterOptions,
|
||||
FormControl,
|
||||
List,
|
||||
|
|
@ -9,6 +9,7 @@ import {
|
|||
ListItemIcon,
|
||||
ListItemSecondaryAction,
|
||||
ListItemText,
|
||||
Stack,
|
||||
styled,
|
||||
TextField,
|
||||
Typography,
|
||||
|
|
@ -19,6 +20,7 @@ import MuiAccordionSummary from "@mui/material/AccordionSummary";
|
|||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FileResponse, FileType } from "../../../../api/explorer.ts";
|
||||
import { FilledTextField, SmallFormControlLabel } from "../../../Common/StyledComponents.tsx";
|
||||
import ClockArrowDownload from "../../../Icons/ClockArrowDownload.tsx";
|
||||
import Eye from "../../../Icons/Eye.tsx";
|
||||
import TableSettingsOutlined from "../../../Icons/TableSettings.tsx";
|
||||
|
|
@ -149,31 +151,38 @@ const ShareSettingContent = ({ setting, file, editing, onSettingChange }: ShareS
|
|||
</ListItemIcon>
|
||||
<ListItemText primary={t("application:modals.privateShare")} />
|
||||
<ListItemSecondaryAction>
|
||||
<Checkbox disabled={editing} checked={setting.is_private} onChange={handleCheck("is_private")} />
|
||||
<Checkbox disabled={editing} checked={!!setting.is_private} onChange={handleCheck("is_private")} />
|
||||
</ListItemSecondaryAction>
|
||||
</StyledListItemButton>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails sx={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
|
||||
<Typography>{t("application:modals.privateShareDes")}</Typography>
|
||||
<Typography variant="body2">{t("application:modals.privateShareDes")}</Typography>
|
||||
{setting.is_private && (
|
||||
<Box sx={{ display: "flex", alignItems: "center", width: "100%" }}>
|
||||
<Stack sx={{ mt: 1, width: "100%" }}>
|
||||
{!editing && (
|
||||
<Checkbox
|
||||
checked={setting.use_custom_password}
|
||||
onChange={() => {
|
||||
onSettingChange({ ...setting, use_custom_password: !setting.use_custom_password });
|
||||
}}
|
||||
<SmallFormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
size="small"
|
||||
checked={setting.use_custom_password}
|
||||
onChange={() => {
|
||||
onSettingChange({ ...setting, use_custom_password: !setting.use_custom_password });
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={t("application:modals.useCustomPassword")}
|
||||
/>
|
||||
)}
|
||||
{!setting.use_custom_password && (
|
||||
<Typography sx={{ flex: 1 }}>{t("application:modals.useCustomPassword")}</Typography>
|
||||
)}
|
||||
{setting.use_custom_password && (
|
||||
<FormControl variant="standard" sx={{ mx: 1, flex: 1 }}>
|
||||
<TextField
|
||||
<Collapse in={setting.use_custom_password}>
|
||||
<FormControl variant="standard" fullWidth sx={{ mt: 1 }}>
|
||||
<FilledTextField
|
||||
label={t("application:modals.sharePassword")}
|
||||
variant="standard"
|
||||
disabled={editing}
|
||||
slotProps={{
|
||||
htmlInput: {
|
||||
maxLength: 32,
|
||||
},
|
||||
}}
|
||||
value={setting.password ?? ""}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value.trim();
|
||||
|
|
@ -181,11 +190,10 @@ const ShareSettingContent = ({ setting, file, editing, onSettingChange }: ShareS
|
|||
onSettingChange({ ...setting, password: value });
|
||||
}}
|
||||
required
|
||||
fullWidth
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
</Box>
|
||||
</Collapse>
|
||||
</Stack>
|
||||
)}
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
|
|
|||
Loading…
Reference in New Issue