diff --git a/.vscode/settings.json b/.vscode/settings.json
index 96e076fd..85423009 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,6 @@
{
"cSpell.words": [
+ "Asyncify",
"dugite",
"fullscreenable",
"maximizable",
diff --git a/package-lock.json b/package-lock.json
index 14c540da..d492c96a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14892,6 +14892,12 @@
"prop-types": "^15.7.2"
}
},
+ "react-async": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/react-async/-/react-async-10.0.1.tgz",
+ "integrity": "sha512-ORUz5ca0B57QgBIzEZM5SuhJ6xFjkvEEs0gylLNlWf06vuVcLZsjIw3wx58jJkZG38p+0nUAxRgFW2b7mnVZzA==",
+ "dev": true
+ },
"react-dom": {
"version": "17.0.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz",
diff --git a/package.json b/package.json
index 1849a274..013a0a5f 100755
--- a/package.json
+++ b/package.json
@@ -181,6 +181,7 @@
"prop-types": "15.7.2",
"react": "17.0.1",
"react-ace": "9.2.1",
+ "react-async": "^10.0.1",
"react-dom": "17.0.1",
"react-i18next": "^11.8.5",
"react-redux": "7.2.2",
diff --git a/src/components/dialog-about/index.tsx b/src/components/dialog-about/index.tsx
deleted file mode 100644
index b4595f75..00000000
--- a/src/components/dialog-about/index.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-import React from 'react';
-import Button from '@material-ui/core/Button';
-import Typography from '@material-ui/core/Typography';
-import DialogContent from '@material-ui/core/DialogContent';
-import connectComponent from '../../helpers/connect-component';
-
-const styles = (theme: any) => ({
- icon: {
- height: 96,
- width: 96,
- },
- dialogContent: {
- minWidth: 320,
- textAlign: 'center',
- },
- title: {
- marginTop: theme.spacing(1),
- },
- version: {
- marginBottom: theme.spacing(2),
- },
- versionSmallContainer: {
- marginTop: theme.spacing(2),
- marginBottom: theme.spacing(2),
- },
- versionSmall: {
- fontSize: '0.8rem',
- },
- goToTheWebsiteButton: {
- marginRight: theme.spacing(1),
- },
- madeBy: {
- marginTop: theme.spacing(2),
- },
- link: {
- fontWeight: 600,
- cursor: 'pointer',
- '&:hover': {
- textDecoration: 'underline',
- },
- },
-});
-interface AboutProps {
- classes: any;
-}
-const About = (props: AboutProps) => {
- const { classes } = props;
- const versions = [
- { name: 'Electron Version', version: window.remote.getEnvironmentVersions().electron },
- { name: 'Node Version', version: window.remote.getEnvironmentVersions().node },
- { name: 'Chromium Version', version: window.remote.getEnvironmentVersions().chrome },
- ];
- return (
-
-
-
-
- TiddlyGit
-
-
- {`Version v${window.remote.getAppVersion()}.`}
-
-
- {versions.map(({ name, version }) => (
-
- {name}: {version}
-
- ))}
-
-
-
-
-
-
-
- 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}
- className={classes.link}>
- 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}
- className={classes.link}>
- WebCatalog
-
-
-
-
- );
-};
-export default connectComponent(About, null, null, styles);
diff --git a/src/helpers/use-service-value.ts b/src/helpers/use-service-value.ts
new file mode 100644
index 00000000..08c094d8
--- /dev/null
+++ b/src/helpers/use-service-value.ts
@@ -0,0 +1,18 @@
+import { useEffect, useState } from 'react';
+
+/**
+ * Use value from service, especially constant value that never changes
+ * This will only update once, won't listen on later update.
+ * @param valuePromise A promise contain the value we want to use in React
+ * @param defaultValue empty array or undefined, as initial value
+ */
+export function usePromiseValue(valuePromise: Promise | (() => Promise), defaultValue?: T): T | undefined {
+ const [value, valueSetter] = useState(defaultValue);
+ useEffect(() => {
+ void (async () => {
+ valueSetter(typeof valuePromise === 'function' ? await valuePromise() : await valuePromise);
+ });
+ }, []);
+
+ return value;
+}
diff --git a/src/pages/About.tsx b/src/pages/About.tsx
new file mode 100644
index 00000000..ec290740
--- /dev/null
+++ b/src/pages/About.tsx
@@ -0,0 +1,119 @@
+import React, { useState, useEffect } from 'react';
+import styled from 'styled-components';
+import { Button, DialogContent } from '@material-ui/core';
+import { usePromiseValue } from '@/helpers/use-service-value';
+
+const Icon = styled.img`
+ height: 96;
+ width: 96;
+`;
+
+const DialogContentSC = styled(DialogContent)`
+ min-width: 320;
+ text-align: 'center';
+`;
+
+const Title = styled.h6`
+ margin-top: 10px;
+`;
+
+const Version = styled.p`
+ margin-bottom: 20px;
+`;
+
+const VersionSmallContainer = styled.div`
+ margin-top: 20px;
+ margin-bottom: 20px;
+`;
+
+const VersionSmall = styled.span`
+ font-size: 0.8rem;
+`;
+
+const GoToTheWebsiteButton = styled(Button)`
+ margin-right: 10px;
+`;
+
+const MadeBy = styled.div`
+ margin-top: 20px;
+`;
+
+const Link = styled.span`
+ font-weight: 600;
+ cursor: pointer;
+ &:hover {
+ text-decoration: underline;
+ }
+`;
+
+export default function About(): JSX.Element {
+ const versions = usePromiseValue(async () => {
+ const processVersions = (await window.service.context.get('environmentVersions')) as NodeJS.ProcessVersions;
+ return [
+ { name: 'Electron Version', version: processVersions.electron },
+ { name: 'Node Version', version: processVersions.node },
+ { name: 'Chromium Version', version: processVersions.chrome },
+ ];
+ }, []);
+
+ const iconPath = usePromiseValue(window.service.context.get('ICON_PATH') as Promise);
+ const appVersion = usePromiseValue(window.service.context.get('appVersion') as Promise);
+
+ return (
+
+
+
+ TiddlyGit
+ {`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
+
+
+
+
+ );
+}
diff --git a/src/preload/common/require-nodejs.ts b/src/preload/common/require-nodejs.ts
index 8f31c9e2..4d39c9d5 100644
--- a/src/preload/common/require-nodejs.ts
+++ b/src/preload/common/require-nodejs.ts
@@ -12,11 +12,6 @@ import { Channels } from '@/constants/channels';
// ipcRenderer.once(channel, listener);
// },
// },
-// getPlatform: () => remote.process.platform,
-// getAppVersion: () => remote.app.getVersion(),
-// getAppName: () => remote.app.name,
-// getOSVersion: () => remote.require('os').release(),
-// getEnvironmentVersions: () => process.versions,
// getGlobal: (key: any) => remote.getGlobal(key),
// useCurrentWindow: (callback: any) => callback(remote.getCurrentWindow()),
// getCurrentWindowID: () => remote.getCurrentWindow().id,
diff --git a/src/renderer.tsx b/src/renderer.tsx
index 3ac473f9..d7e834ea 100644
--- a/src/renderer.tsx
+++ b/src/renderer.tsx
@@ -22,7 +22,7 @@ import { initI18N } from './i18n';
import AppWrapper from './components/app-wrapper';
-const DialogAbout = React.lazy(async () => await import('./components/dialog-about'));
+const AboutPage = React.lazy(async () => await import('./pages/About'));
const DialogAddWorkspace = React.lazy(async () => await import('./components/dialog-add-workspace'));
const DialogAuth = React.lazy(async () => await import('./components/dialog-auth'));
const DialogCodeInjection = React.lazy(async () => await import('./components/dialog-code-injection'));
@@ -41,7 +41,7 @@ const App = (): JSX.Element => {
switch (window.meta.windowName) {
case WindowNames.about:
document.title = 'About';
- return ;
+ return ;
case WindowNames.addWorkspace:
document.title = 'Add Workspace';
return ;
diff --git a/src/services/constants/index.ts b/src/services/constants/index.ts
index a6598e17..8fbc026d 100644
--- a/src/services/constants/index.ts
+++ b/src/services/constants/index.ts
@@ -1,5 +1,8 @@
-import { injectable } from 'inversify';
+import { app } from 'electron';
+import process from 'process';
+import os from 'os';
import isDevelopment from 'electron-is-dev';
+import { injectable } from 'inversify';
import { IContextService, IContext, IPaths, IConstants } from './interface';
import * as paths from '@services/constants/paths';
@@ -9,6 +12,11 @@ export class ContextService implements IContextService {
pathConstants: IPaths = paths;
constants: IConstants = {
isDevelopment,
+ platform: process.platform,
+ appVersion: app.getVersion(),
+ appName: app.name,
+ oSVersion: os.release(),
+ environmentVersions: process.versions,
};
public get(key: K): IContext[K] {
diff --git a/src/services/constants/interface.ts b/src/services/constants/interface.ts
index 8f1dd532..61e33666 100644
--- a/src/services/constants/interface.ts
+++ b/src/services/constants/interface.ts
@@ -16,9 +16,14 @@ export interface IPaths {
*/
export interface IConstants {
isDevelopment: boolean;
+ platform: string;
+ appVersion: string;
+ appName: string;
+ oSVersion: string;
+ environmentVersions: NodeJS.ProcessVersions;
}
-export type IContext = IPaths | IConstants;
+export interface IContext extends IPaths, IConstants {}
/**
* Manage constant value like `isDevelopment` and many else, so you can know about about running environment in main and renderer process easily.