diff --git a/localization/locales/en/translation.json b/localization/locales/en/translation.json index 625cf75d..f42c45b9 100644 --- a/localization/locales/en/translation.json +++ b/localization/locales/en/translation.json @@ -100,8 +100,10 @@ "Hibernate": "Save CPU usage, memory and battery.", "SelectLocal": "Select Local Image...", "ResetDefaultIcon": "Reset Default Icon", + "NoRevert": "Caution! This operation can't be reverted.", "URL": "Wiki URL", - "Port": "Local host server port" + "Port": "Local host server port", + "PathDescription": "Location of your local wiki folder." }, "Dialog": { "CantFindWorkspaceFolderRemoveWorkspace": "Cannot find the workspace folder that was still there before! \nThe folders that should have existed here may have been removed! \nDo you want to remove the workspace?", @@ -114,7 +116,8 @@ "StorageServiceUserInfoNoFoundDetail": "Seems you haven't login to Your storage service, so we disable syncing for this wiki.", "RestartMessage": "You need to restart the app for this change to take affect.", "Later": "Later", - "RestartNow": "Restart Now" + "RestartNow": "Restart Now", + "MadeWithLove":"<0>Made with <1>❤<2> by " }, "Log": { "CantSyncGitNotInitialized": "Unable to sync, this folder is not initialized as a Git repository", @@ -232,5 +235,6 @@ }, "Loading": "Loading", "Yes": "Yes", - "No": "No" + "No": "No", + "LinOnetwo": "Lin Onetwo" } diff --git a/localization/locales/zh_CN/translation.json b/localization/locales/zh_CN/translation.json index 2a0087d6..d7f60f57 100644 --- a/localization/locales/zh_CN/translation.json +++ b/localization/locales/zh_CN/translation.json @@ -100,8 +100,10 @@ "DisableNotification": "阻止工作区的消息提醒", "SelectLocal": "选择本地图片...", "ResetDefaultIcon": "还原默认图标", + "NoRevert": "注意!这个操作无法撤销!", "URL": "本地服务器地址", - "Port": "本地服务器端口" + "Port": "本地服务器端口", + "PathDescription": "本地维基文件夹的地址" }, "Log": { "StartGitInitialization": "开始初始化本地Git仓库", @@ -148,7 +150,8 @@ "StorageServiceUserInfoNoFoundDetail": "似乎你尚未登录存储备份服务,因此此 Wiki 的同步暂时禁用,直到你登录以提供有可用于同步的登录信息。", "Later": "稍后", "RestartMessage": "您需要重新启动本程序才能使此更改生效。", - "RestartNow": "现在重启" + "RestartNow": "现在重启", + "MadeWithLove":"<0>有<1> ❤ <2>的开发者:" }, "Cancel": "取消", "Preference": { @@ -222,7 +225,7 @@ "SpellCheck": "拼写检查", "SpellCheckLanguages": "首选拼写检查语言", "Support": "支持", - "TiddlyWiki": "微分维基(TiddlyWiki)", + "TiddlyWiki": "滴粒维基(TiddlyWiki)", "System": "系统", "TranslatiumIntro": "像大佬一样翻译任何语言", "HowToEnableNotifications": "<0>TiddlyGit支持原生通知功能。但在某些情况下,要接收通知,您需要手动配置一些Web应用设置。<1>了解详情<2>。", diff --git a/localization/locales/zh_CN/translation.missing.json b/localization/locales/zh_CN/translation.missing.json index 9e26dfee..321b3a65 100644 --- a/localization/locales/zh_CN/translation.missing.json +++ b/localization/locales/zh_CN/translation.missing.json @@ -1 +1 @@ -{} \ No newline at end of file +{"LinOnetwo":"LinOnetwo"} \ No newline at end of file diff --git a/src/helpers/useServiceValue.ts b/src/helpers/useServiceValue.ts index bc24cc0f..f5ebf87d 100644 --- a/src/helpers/useServiceValue.ts +++ b/src/helpers/useServiceValue.ts @@ -10,6 +10,7 @@ import { AsyncReturnType } from 'type-fest'; export function usePromiseValue( asyncValue: () => Promise, defaultValue?: AsyncReturnType, + dependency: unknown[] = [], ): T | DefaultValueType { const [value, valueSetter] = useState(defaultValue as T | DefaultValueType); // use initial value @@ -17,7 +18,7 @@ export function usePromiseValue( void (async () => { valueSetter(await asyncValue()); })(); - }, []); + }, dependency); return value; } diff --git a/src/pages/About.tsx b/src/pages/About.tsx index c1a5340c..e9e5cb12 100644 --- a/src/pages/About.tsx +++ b/src/pages/About.tsx @@ -1,35 +1,51 @@ import React from 'react'; import styled from 'styled-components'; -import { Button, DialogContent } from '@material-ui/core'; +import { Trans, useTranslation } from 'react-i18next'; +import { Button, DialogContent as DialogContentRaw } from '@material-ui/core'; import { usePromiseValue } from '@/helpers/useServiceValue'; -const Icon = styled.img` - height: 96; - width: 96; +const DialogContent = styled(DialogContentRaw)` + min-width: 320px; + text-align: 'center'; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; `; -const DialogContentSC = styled(DialogContent)` - min-width: 320; - text-align: 'center'; +const Icon = styled.img` + height: 96px; + width: 96px; `; const Title = styled.h6` margin-top: 10px; `; -const Version = styled.p` +const TiddlyGitVersion = styled.p` + margin-top: 0; margin-bottom: 20px; + text-align: center; `; -const VersionSmallContainer = styled.div` - margin-top: 20px; +const DependenciesVersionsContainer = styled.div` + margin-top: 0px; margin-bottom: 20px; + flex-direction: column; + justify-content: center; + align-items: center; `; -const VersionSmall = styled.span` +const DependenciesVersions = styled.div` font-size: 0.8rem; + text-align: center; `; +const ButtonContainer = styled.div` + display: flex; + flex-direction: row; + justify-content: center; +`; const GoToTheWebsiteButton = styled(Button)` margin-right: 10px; `; @@ -47,6 +63,7 @@ const Link = styled.span` `; export default function About(): JSX.Element { + const { t } = useTranslation(); const versions = usePromiseValue(async () => { const processVersions = (await window.service.context.get('environmentVersions')) as NodeJS.ProcessVersions; return [ @@ -61,60 +78,61 @@ export default function About(): JSX.Element { const platform = usePromiseValue(async () => (await window.service.context.get('platform')) as string); return ( -
- - - TiddlyGit ({platform ?? 'Unknown Platform'}) - {`Version v${appVersion ?? ' - '}.`} - - {versions?.map(({ name, version }) => ( - - {name}: {version} - - ))} - + + + TiddlyGit ({platform ?? 'Unknown Platform'}) + {`Version v${appVersion ?? ' - '}.`} + + {versions?.map(({ name, version }) => ( + + {name}: {version} + + ))} + + await window.service.native.open('https://github.com/tiddly-gittly/TiddlyGit-Desktop')}> Website -
await window.service.native.open('https://github.com/tiddly-gittly/TiddlyGit-Desktop/issues/new/choose')}> Support +
- + + Made with by - await window.service.native.open('https://onetwo.ren/wiki/')} - onKeyDown={async (event) => { - if (event.key !== 'Enter') { - return; - } - await window.service.native.open('https://onetwo.ren/wiki/'); - }} - role="link" - tabIndex={0}> - Lin Onetwo - - and - await window.service.native.open('https://webcatalog.app/?utm_source=tiddlygit_app')} - onKeyDown={async (event) => { - if (event.key !== 'Enter') { - return; - } - await window.service.native.open('https://webcatalog.app/?utm_source=tiddlygit_app'); - }} - role="link" - tabIndex={0}> - WebCatalog - - -
-
+ + await window.service.native.open('https://onetwo.ren/wiki/')} + onKeyDown={async (event) => { + if (event.key !== 'Enter') { + return; + } + await window.service.native.open('https://onetwo.ren/wiki/'); + }} + role="link" + tabIndex={0}> + {t('LinOnetwo')} + + && + await window.service.native.open('https://webcatalog.app/?utm_source=tiddlygit_app')} + onKeyDown={async (event) => { + if (event.key !== 'Enter') { + return; + } + await window.service.native.open('https://webcatalog.app/?utm_source=tiddlygit_app'); + }} + role="link" + tabIndex={0}> + {t('Preference.WebCatalog')} + + + ); } diff --git a/src/pages/EditWorkspace/index.tsx b/src/pages/EditWorkspace/index.tsx index 7e646b02..0c165730 100644 --- a/src/pages/EditWorkspace/index.tsx +++ b/src/pages/EditWorkspace/index.tsx @@ -1,18 +1,21 @@ /* eslint-disable @typescript-eslint/strict-boolean-expressions */ /* eslint-disable unicorn/no-null */ -import React, { useState, useEffect } from 'react'; +import React from 'react'; import styled, { css } from 'styled-components'; import { useTranslation } from 'react-i18next'; -import ButtonRaw from '@material-ui/core/Button'; -import TextFieldRaw from '@material-ui/core/TextField'; -import Divider from '@material-ui/core/Divider'; -import List from '@material-ui/core/List'; -import ListItem from '@material-ui/core/ListItem'; -import ListItemText from '@material-ui/core/ListItemText'; -import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction'; -import Switch from '@material-ui/core/Switch'; -import Typography from '@material-ui/core/Typography'; -import Autocomplete from '@material-ui/lab/Autocomplete'; +import { + Tooltip, + Button as ButtonRaw, + TextField as TextFieldRaw, + Divider, + List as ListRaw, + ListItem, + ListItemText, + ListItemSecondaryAction, + Switch, + Typography, +} from '@material-ui/core'; +import { Autocomplete } from '@material-ui/lab'; import defaultIcon from '../../images/default-icon.png'; import type { ISubWikiPluginContent } from '@services/wiki/update-plugin-content'; @@ -20,11 +23,11 @@ import { WindowNames, WindowMeta } from '@services/windows/WindowProperties'; import { usePromiseValue } from '@/helpers/useServiceValue'; import { useWorkspaceObservable } from '@services/workspaces/hooks'; import { useForm } from './formHook'; +import { IWorkspace } from '@services/workspaces/interface'; const Root = styled.div` - background: #fffff0; - height: 100vh; - width: 100vw; + height: 100%; + width: 100%; padding: 20px; display: flex; flex-direction: column; @@ -37,18 +40,19 @@ const Button = styled(ButtonRaw)` margin-left: 10px; `; const TextField = styled(TextFieldRaw)` - margin-bottom: 30px; + margin-bottom: 10px; `; TextField.defaultProps = { fullWidth: true, margin: 'dense', - variant: 'outlined', + size: 'small', + variant: 'filled', InputLabelProps: { shrink: true, }, }; const AvatarFlex = styled.div` - display: 'flex'; + display: flex; `; const AvatarLeft = styled.div` padding-top: 10px; @@ -58,6 +62,10 @@ const AvatarLeft = styled.div` `; const AvatarRight = styled.div` flex: 1; + display: flex; + flex-direction: column; + justify-content: space-around; + align-items: flex-start; padding-top: 10px; padding-bottom: 10px; padding-left: 10px; @@ -67,10 +75,9 @@ const AvatarRight = styled.div` * border: theme.palette.type === 'dark' ? 'none': '1px solid rgba(0, 0, 0, 0.12)'; * */ const Avatar = styled.div<{ transparentBackground?: boolean }>` - height: 85; - width: 85; - background: white; - border-radius: 4; + height: 85px; + width: 85px; + border-radius: 4px; color: #333; font-size: 32px; line-height: 64px; @@ -94,10 +101,8 @@ const AvatarPicture = styled.img` height: 100%; width: 100%; `; -const ButtonBot = styled(ButtonRaw)` - margin-top: 10px; -`; -ButtonBot.defaultProps = { +const PictureButton = styled(ButtonRaw)``; +PictureButton.defaultProps = { variant: 'outlined', size: 'small', }; @@ -107,6 +112,12 @@ const Caption = styled(Typography)` Caption.defaultProps = { variant: 'caption', }; +const List = styled(ListRaw)` + & > li > div { + padding-top: 0; + padding-bottom: 0; + } +`; const getValidIconPath = (iconPath?: string | null): string => { if (typeof iconPath === 'string') { @@ -116,21 +127,12 @@ const getValidIconPath = (iconPath?: string | null): string => { }; const workspaceID = (window.meta as WindowMeta[WindowNames.editWorkspace]).workspaceID as string; +const wikiPictureExtensions = ['jpg', 'jpeg', 'png', 'gif', 'tiff', 'tif', 'bmp', 'dib']; export default function EditWorkspace(): JSX.Element { const { t } = useTranslation(); - const fileSystemPaths = usePromiseValue( - async () => await window.service.wiki.getSubWikiPluginContent(mainWikiToLink), - [], - ) as ISubWikiPluginContent[]; const originalWorkspace = useWorkspaceObservable(workspaceID); const [workspace, workspaceSetter, onSave] = useForm(originalWorkspace); - if (workspaceID === undefined) { - return Error {workspaceID ?? '-'} not exists; - } - if (workspace === undefined) { - return Loading...; - } const { mainWikiToLink, isSubWiki, @@ -143,13 +145,25 @@ export default function EditWorkspace(): JSX.Element { disableAudio, disableNotifications, homeUrl, - } = workspace; + } = ((workspace ?? {}) as unknown) as IWorkspace; + const fileSystemPaths = usePromiseValue( + async () => (mainWikiToLink ? await window.service.wiki.getSubWikiPluginContent(mainWikiToLink) : []), + [], + [mainWikiToLink], + ) as ISubWikiPluginContent[]; + if (workspaceID === undefined) { + return Error {workspaceID ?? '-'} not exists; + } + if (workspace === undefined) { + return Loading...; + } return ( workspaceSetter({ ...workspace, name: event.target.value })} @@ -168,13 +182,15 @@ export default function EditWorkspace(): JSX.Element { }} /> )} - fileSystemPath.tagName)} - value={tagName} - onInputChange={(_, value) => workspaceSetter({ ...workspace, tagName: value })} - renderInput={(parameters) => } - /> + {isSubWiki && ( + fileSystemPath.tagName)} + value={tagName} + onInputChange={(_, value) => workspaceSetter({ ...workspace, tagName: value })} + renderInput={(parameters) => } + /> + )} @@ -182,24 +198,25 @@ export default function EditWorkspace(): JSX.Element { - - PNG, JPEG, GIF, TIFF or BMP. + + { + const filePaths = await window.service.native.pickFile([{ name: 'Images', extensions: wikiPictureExtensions }]); + if (filePaths.length > 0) { + await window.service.workspace.update(workspaceID, { picturePath: filePaths[0] }); + } + }}> + {t('EditWorkspace.SelectLocal')} + + - workspaceSetter({ ...workspace, picturePath: null })} disabled={!picturePath}> - {t('EditWorkspace.ResetDefaultIcon')} - + + workspaceSetter({ ...workspace, picturePath: null })} disabled={!picturePath}> + {t('EditWorkspace.ResetDefaultIcon')} + + {!isSubWiki && ( diff --git a/src/pages/Main/index.tsx b/src/pages/Main/index.tsx index ca5e197e..ff7bfcc1 100644 --- a/src/pages/Main/index.tsx +++ b/src/pages/Main/index.tsx @@ -1,5 +1,6 @@ import React, { useCallback } from 'react'; import styled, { css } from 'styled-components'; +import { useTranslation } from 'react-i18next'; import { AsyncReturnType } from 'type-fest'; import { DndContext } from '@dnd-kit/core'; import { SortableContext, arrayMove, verticalListSortingStrategy } from '@dnd-kit/sortable'; @@ -146,7 +147,7 @@ const Tip2 = styled.div` user-select: none; `; -const End = styled.div` +const SideBarEnd = styled.div` display: flex; flex-direction: column; `; @@ -166,6 +167,7 @@ const SidebarContainer = ({ children }: { children: React.ReactNode }): JSX.Elem }; export default function Main(): JSX.Element { + const { t } = useTranslation(); const workspacesList = useWorkspacesListObservable(); const [{ attachToMenubar, titleBar, sidebar, pauseNotifications, themeSource }, isFullScreen] = usePromiseValue<[Partial, boolean | undefined]>( async () => await Promise.all([window.service.preference.getPreferences(), window.service.window.isFullScreen()]), @@ -218,16 +220,14 @@ export default function Main(): JSX.Element { )} void window.service.window.open(WindowNames.addWorkspace)} /> - - await window.service.window.open(WindowNames.notifications)}> + + await window.service.window.open(WindowNames.notifications)}> {typeof pauseNotifications === 'string' && pauseNotifications.length > 0 ? : } - {attachToMenubar === true && ( - await window.service.window.open(WindowNames.preferences)}> - - - )} - + await window.service.window.open(WindowNames.preferences)}> + + + )} diff --git a/src/services/windows/WindowProperties.ts b/src/services/windows/WindowProperties.ts index 31ce0627..8f0ef3f6 100644 --- a/src/services/windows/WindowProperties.ts +++ b/src/services/windows/WindowProperties.ts @@ -43,7 +43,7 @@ export const windowDimension: Record