feat: Move new user helps to Guide page

This commit is contained in:
lin onetwo 2023-07-08 18:19:51 +08:00
parent aefd9dcd88
commit b790f7b97c
12 changed files with 95 additions and 25 deletions

View file

@ -1,4 +1,5 @@
import AccountTreeIcon from '@material-ui/icons/AccountTree';
import InfoIcon from '@material-ui/icons/Info';
import { PageType } from '@services/pages/interface';
export function getBuildInPageIcon(pageType: PageType): JSX.Element {
@ -10,5 +11,9 @@ export function getBuildInPageIcon(pageType: PageType): JSX.Element {
case PageType.workflow: {
return <AccountTreeIcon />;
}
case PageType.guide: {
return <InfoIcon />;
}
}
// don't return null here. If you get `Function lacks ending return statement and return type does not include 'undefined'.ts(2366)`, you must forget to provide an icon for a newly added page type here.
}

44
src/pages/Guide/index.tsx Normal file
View file

@ -0,0 +1,44 @@
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
/* eslint-disable @typescript-eslint/promise-function-async */
import { Typography } from '@material-ui/core';
import { useTranslation } from 'react-i18next';
import styled from 'styled-components';
import { usePreferenceObservable } from '@services/preferences/hooks';
import { useWorkspacesListObservable } from '@services/workspaces/hooks';
import { useState } from 'react';
import { Languages } from '../Preferences/sections/Languages';
import { TiddlyWiki } from '../Preferences/sections/TiddlyWiki';
import { NewUserMessage } from './NewUserMessage';
import { useAutoCreateFirstWorkspace } from './useAutoCreateFirstWorkspace';
const InnerContentRoot = styled.div`
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10px;
width: 100%;
height: 100%;
`;
export function Guide(): JSX.Element {
const { t } = useTranslation();
const workspacesList = useWorkspacesListObservable();
const [wikiCreationMessage, wikiCreationMessageSetter] = useState('');
useAutoCreateFirstWorkspace(workspacesList, wikiCreationMessageSetter);
const preferences = usePreferenceObservable();
return (
<>
<InnerContentRoot>
{wikiCreationMessage && <Typography color='textSecondary'>{wikiCreationMessage}</Typography>}
{preferences !== undefined && Array.isArray(workspacesList) && workspacesList.length === 0 && (
<NewUserMessage sidebar={preferences.sidebar} themeSource={preferences.themeSource} />
)}
</InnerContentRoot>
<Languages languageSelectorOnly />
<TiddlyWiki />
</>
);
}

View file

@ -34,7 +34,7 @@ export function useAutoCreateFirstWorkspace(workspacesList: IWorkspaceWithMetada
if (DEFAULT_WIKI_FOLDER === undefined || DEFAULT_FIRST_WIKI_PATH === undefined) return;
if (workspacesList?.length === 0) {
createdSetter(true);
void onSubmit();
void onSubmit()
}
}, [workspacesList?.length, created, createdSetter, onSubmit, DEFAULT_WIKI_FOLDER, DEFAULT_FIRST_WIKI_PATH]);
}

View file

@ -14,6 +14,7 @@ import { WindowNames } from '@services/windows/WindowProperties';
import FindInPage from '../../components/FindInPage';
import { SideBar } from '../../components/Sidebar';
import { WikiBackground } from '../WikiBackground';
import { Guide } from '../Guide';
const Workflow = lazy(() => import('../Workflow'));
@ -78,11 +79,10 @@ export default function Main(): JSX.Element {
<FindInPage />
<Switch>
<Route path={`/${WindowNames.main}/${PageType.wiki}/:id/`} component={WikiBackground} />
<Route path={`/${WindowNames.main}/${PageType.guide}/:id/`} component={Guide} />
<Route path={`/${WindowNames.main}/${PageType.workflow}/:id/`} component={Workflow} />
<Route path={`/${WindowNames.main}`} component={WikiBackground} />
<Route>
<div>{t('Loading')}(Main)</div>
</Route>
<Route path={`/${WindowNames.main}`} component={Guide} />
<Route component={Guide} />
</Switch>
</ContentRoot>
</Root>

View file

@ -4,14 +4,10 @@ import { Typography } from '@material-ui/core';
import { useTranslation } from 'react-i18next';
import styled from 'styled-components';
import { usePreferenceObservable } from '@services/preferences/hooks';
import { useWorkspacesListObservable } from '@services/workspaces/hooks';
import { useState } from 'react';
import { useAutoCreateFirstWorkspace } from '../Main/useAutoCreateFirstWorkspace';
import { Languages } from '../Preferences/sections/Languages';
import { TiddlyWiki } from '../Preferences/sections/TiddlyWiki';
import { useAutoCreateFirstWorkspace } from '../Guide/useAutoCreateFirstWorkspace';
import { ViewLoadErrorMessages, WikiErrorMessages } from './ErrorMessage';
import { NewUserMessage } from './NewUserMessage';
const InnerContentRoot = styled.div`
flex: 1;
@ -37,10 +33,6 @@ export function WikiBackground(): JSX.Element {
activeWorkspaceMetadata?.isLoading === false;
const [wikiCreationMessage, wikiCreationMessageSetter] = useState('');
useAutoCreateFirstWorkspace(workspacesList, wikiCreationMessageSetter);
const preferences = usePreferenceObservable();
if (preferences === undefined) return <div>{t('Loading')}</div>;
const { sidebar, themeSource } = preferences;
return (
<>
<InnerContentRoot>
@ -50,10 +42,7 @@ export function WikiBackground(): JSX.Element {
)}
{Array.isArray(workspacesList) && workspacesList.length > 0 && activeWorkspaceMetadata?.isLoading === true && <Typography color='textSecondary'>{t('Loading')}</Typography>}
{wikiCreationMessage && <Typography color='textSecondary'>{wikiCreationMessage}</Typography>}
{Array.isArray(workspacesList) && workspacesList.length === 0 && <NewUserMessage sidebar={sidebar} themeSource={themeSource} />}
</InnerContentRoot>
<Languages languageSelectorOnly />
<TiddlyWiki />
</>
);
}

View file

@ -1,6 +1,5 @@
/* eslint-disable @typescript-eslint/promise-function-async */
import { WindowNames } from '@services/windows/WindowProperties';
import { t } from 'i18next';
import { lazy, useEffect } from 'react';
import { Route, Switch, useLocation } from 'wouter';
@ -26,9 +25,7 @@ export function Pages(): JSX.Element {
<Route path={`/${WindowNames.preferences}`} component={DialogPreferences} />
<Route path={`/${WindowNames.spellcheck}`} component={SpellcheckLanguages} />
<Route path={`/${WindowNames.main}/:any*/:any*`} component={Main} />
<Route>
<div>{t('Loading')}(index)</div>
</Route>
<Route component={Main} />
</Switch>
);
}

View file

@ -1,10 +1,21 @@
import { PageType } from './interface';
import { IPage, PageType } from './interface';
export const defaultBuildInPages = {
/**
* Add React component route for build-in pages in `src/pages/Main/index.tsx`
*/
export const defaultBuildInPages: Record<string, IPage> = {
workflow: {
type: PageType.workflow,
id: PageType.workflow,
active: false,
hide: false,
order: 0,
},
guide: {
type: PageType.guide,
id: PageType.guide,
active: false,
hide: false,
order: 0,
},
};

View file

@ -9,5 +9,8 @@ export function getBuildInPageName(pageType: PageType, t: TFunction) {
case PageType.workflow: {
return t('Workflow.Title');
}
case PageType.guide: {
return t('WorkspaceSelector.Guide');
}
}
}

View file

@ -38,11 +38,17 @@ export class Pages implements IPagesService {
* load pages in sync, and ensure it is an Object
*/
private getInitPagesForCache(): Record<string, IPage> {
const pagesFromDisk = settings.getSync(`pages`) ?? defaultBuildInPages;
const pagesFromDisk = settings.getSync(`pages`) ?? {};
const loadedPages = typeof pagesFromDisk === 'object' && !Array.isArray(pagesFromDisk)
? pickBy(pagesFromDisk, (value) => value !== null) as unknown as Record<string, IPage>
: {};
return loadedPages;
return this.sanitizePageSettings(loadedPages);
}
private sanitizePageSettings(pages: Record<string, IPage>): Record<string, IPage> {
// assign newly added default page setting to old user config, if user config missing a key (id of newly added build-in page)
const sanitizedPages = { ...defaultBuildInPages, ...pages };
return sanitizedPages;
}
public async setActivePage(id: string | PageType, oldActivePageID: string | PageType | undefined): Promise<void> {

View file

@ -3,11 +3,25 @@ import { ProxyPropertyType } from 'electron-ipc-cat/common';
import { BehaviorSubject } from 'rxjs';
export enum PageType {
/**
* Default empty page, have some user guide and new user settings.
*/
guide = 'guide',
/**
* All "workspaces". It is hard to merge workspace concept with page concept, because will need to migrate all user data. So we leave them to be still workspace, but also call them wiki pages. And in event listeners about wiki page, we redirect them to call workspace methods.
*/
wiki = 'wiki',
/**
* AI workflow
*/
workflow = 'workflow',
}
export interface IPage {
active: boolean;
/**
* User can hide a page's button from sidebar if they don't want to see it.
*/
hide: boolean;
/**
* Wiki's workspaceID, or just be build-in page's type.
*/

View file

@ -397,6 +397,7 @@ export class Workspace implements IWorkspaceService {
}
// switch from page to workspace, clear active page to switch to WikiBackground page
const activePage = this.pagesService.getActivePageSync();
// instead of switch to a wiki workspace, we simply clear active page, because wiki page logic is not implemented yet, we are still using workspace logic.
await this.pagesService.clearActivePage(activePage?.id);
}