refactor: new About page

This commit is contained in:
tiddlygit-test 2021-02-13 16:21:10 +08:00
parent 7bcb5b5b34
commit 7a8aff80c4
10 changed files with 162 additions and 122 deletions

View file

@ -1,5 +1,6 @@
{
"cSpell.words": [
"Asyncify",
"dugite",
"fullscreenable",
"maximizable",

6
package-lock.json generated
View file

@ -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",

View file

@ -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",

View file

@ -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 (
<div>
<DialogContent className={classes.dialogContent}>
<img src={`file:///${(window.meta as any).iconPath}`} alt="TiddlyGit" className={classes.icon} />
<Typography variant="h6" className={classes.title}>
TiddlyGit
</Typography>
<Typography variant="body2" className={classes.version}>
{`Version v${window.remote.getAppVersion()}.`}
</Typography>
<div className={classes.versionSmallContainer}>
{versions.map(({ name, version }) => (
<Typography key={name} variant="body2" className={classes.versionSmall}>
{name}: {version}
</Typography>
))}
</div>
<Button onClick={async () => await window.service.native.open('https://github.com/tiddly-gittly/TiddlyGit-Desktop')}>Website</Button>
<br />
<Button onClick={async () => await window.service.native.open('https://github.com/tiddly-gittly/TiddlyGit-Desktop/issues/new/choose')}>Support</Button>
<Typography variant="body2" className={classes.madeBy}>
<span>Made with </span>
<span role="img" aria-label="love">
</span>
<span> by </span>
<span
onClick={async () => 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
</span>
<span> and </span>
<span
onClick={async () => 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
</span>
</Typography>
</DialogContent>
</div>
);
};
export default connectComponent(About, null, null, styles);

View file

@ -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<T>(valuePromise: Promise<T> | (() => Promise<T>), defaultValue?: T): T | undefined {
const [value, valueSetter] = useState<T | undefined>(defaultValue);
useEffect(() => {
void (async () => {
valueSetter(typeof valuePromise === 'function' ? await valuePromise() : await valuePromise);
});
}, []);
return value;
}

119
src/pages/About.tsx Normal file
View file

@ -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<string | undefined>(window.service.context.get('ICON_PATH') as Promise<string>);
const appVersion = usePromiseValue<string | undefined>(window.service.context.get('appVersion') as Promise<string>);
return (
<div>
<DialogContentSC>
<Icon src={iconPath} alt="TiddlyGit" />
<Title>TiddlyGit</Title>
<Version>{`Version v${appVersion ?? ' - '}.`}</Version>
<VersionSmallContainer>
{versions?.map(({ name, version }) => (
<VersionSmall key={name}>
{name}: {version}
</VersionSmall>
))}
</VersionSmallContainer>
<GoToTheWebsiteButton onClick={async () => await window.service.native.open('https://github.com/tiddly-gittly/TiddlyGit-Desktop')}>
Website
</GoToTheWebsiteButton>
<br />
<GoToTheWebsiteButton onClick={async () => await window.service.native.open('https://github.com/tiddly-gittly/TiddlyGit-Desktop/issues/new/choose')}>
Support
</GoToTheWebsiteButton>
<MadeBy>
<span>Made with </span>
<span role="img" aria-label="love">
</span>
<span> by </span>
<Link
onClick={async () => 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
</Link>
<span> and </span>
<Link
onClick={async () => 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
</Link>
</MadeBy>
</DialogContentSC>
</div>
);
}

View file

@ -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,

View file

@ -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 <DialogAbout />;
return <AboutPage />;
case WindowNames.addWorkspace:
document.title = 'Add Workspace';
return <DialogAddWorkspace />;

View file

@ -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<K extends keyof IContext>(key: K): IContext[K] {

View file

@ -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.