mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-06 02:30:47 -08:00
feat: add new help page showing learning resources
This commit is contained in:
parent
38d86f96ea
commit
717fa07575
12 changed files with 166 additions and 5 deletions
|
|
@ -3,6 +3,7 @@
|
|||
"WorkspaceSelector": {
|
||||
"Add": "Add",
|
||||
"Guide": "Guide",
|
||||
"Help": "Help",
|
||||
"OpenWorkspaceTagTiddler": "Open {{tagName}}",
|
||||
"DefaultTiddlers": "Default Tiddlers",
|
||||
"OpenWorkspaceMenuName": "Open Workspace",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
"WorkspaceSelector": {
|
||||
"Add": "添加",
|
||||
"Guide": "引导",
|
||||
"Help": "帮助",
|
||||
"OpenWorkspaceTagTiddler": "打开 {{tagName}}",
|
||||
"DefaultTiddlers": "默认条目",
|
||||
"OpenWorkspaceMenuName": "打开工作区",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { useLocation } from 'wouter';
|
|||
|
||||
import { getBuildInPageName } from '@services/pages/getBuildInPageName';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import { getBuildInPageIcon } from './getBuildInPageIcon';
|
||||
import { getBuildInPageIcon } from '../../services/pages/getBuildInPageIcon';
|
||||
import { PageSelectorBase } from './PageSelectorBase';
|
||||
|
||||
export interface ISortableItemProps {
|
||||
|
|
|
|||
77
src/pages/Help/HelpWebsiteItem.tsx
Normal file
77
src/pages/Help/HelpWebsiteItem.tsx
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* eslint-disable unicorn/no-null */
|
||||
import { Button, Menu, MenuItem } from '@mui/material';
|
||||
import { WindowNames } from '@services/windows/WindowProperties';
|
||||
import React, { useState } from 'react';
|
||||
import { styled } from 'styled-components';
|
||||
|
||||
const StyledGridItem = styled.div`
|
||||
// Add styles for your grid item here
|
||||
`;
|
||||
|
||||
interface HelpWebsiteItemProps {
|
||||
item: {
|
||||
description: string;
|
||||
fallbackUrls: string[];
|
||||
title: string;
|
||||
url: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const HelpWebsiteItem: React.FC<HelpWebsiteItemProps> = ({ item }) => {
|
||||
const [anchorElement, setAnchorElement] = useState<null | HTMLElement>(null);
|
||||
|
||||
const openExternalLink = (uri: string) => {
|
||||
void window.service.window.open(WindowNames.any, { uri });
|
||||
};
|
||||
|
||||
const handleOpenMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorElement(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleCloseMenu = () => {
|
||||
setAnchorElement(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledGridItem>
|
||||
<h3>{item.title}</h3>
|
||||
<p>{item.description}</p>
|
||||
<Button
|
||||
onClick={() => {
|
||||
openExternalLink(item.url);
|
||||
}}
|
||||
>
|
||||
Open
|
||||
</Button>
|
||||
{item.fallbackUrls.length > 0 && (
|
||||
<>
|
||||
<Button
|
||||
aria-controls='fallback-menu'
|
||||
aria-haspopup='true'
|
||||
onClick={handleOpenMenu}
|
||||
>
|
||||
Alternatives
|
||||
</Button>
|
||||
<Menu
|
||||
id='fallback-menu'
|
||||
anchorEl={anchorElement}
|
||||
keepMounted
|
||||
open={Boolean(anchorElement)}
|
||||
onClose={handleCloseMenu}
|
||||
>
|
||||
{item.fallbackUrls.map((url, index) => (
|
||||
<MenuItem
|
||||
key={index}
|
||||
onClick={() => {
|
||||
openExternalLink(url);
|
||||
}}
|
||||
>
|
||||
{new URL(url).hostname}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
</>
|
||||
)}
|
||||
</StyledGridItem>
|
||||
);
|
||||
};
|
||||
10
src/pages/Help/helpPages.json
Normal file
10
src/pages/Help/helpPages.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"onlineSources": [
|
||||
"tidgi.fun/recipes/default/tiddlers.json?filter=[tag[HelpPage]]"
|
||||
],
|
||||
"default": [
|
||||
{"title":"Tiddlywiki XP", "description": "「一个快速体验太微的机会」—— 非常全面、易读,包括了很多非常基础的操作,例如「如何新建第一个笔记」","tags":"Intro","url":"https://keatonlao.gitee.io/tiddlywiki-xp/", "fallbackUrls": "https://keatonlao.github.io/tiddlywiki-xp/", "language": "zh-Hans"},
|
||||
{"title":"Grok TiddlyWiki", "description": "Build a deep, lasting understanding of TiddlyWiki","tags":"Intro FAQ","url":"https://groktiddlywiki.com/read/", "language": "en-GB"},
|
||||
{"title":"太微中文教程", "description": "中文社区共建的TiddlyWiki教程,体验从入门到知识管理大师之路","tags":"Intro","url":"https://tw-cn.netlify.app/", "fallbackUrls": "https://tw-cn.cpolar.top/ https://tiddly-wiki-chinese-tutorial.vercel.app/ https://tiddly-gittly.github.io/TiddlyWiki-Chinese-Tutorial/", "language": "zh-Hans"}
|
||||
]
|
||||
}
|
||||
16
src/pages/Help/index.tsx
Normal file
16
src/pages/Help/index.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { Grid } from '@mui/material';
|
||||
import { HelpWebsiteItem } from './HelpWebsiteItem';
|
||||
import { useLoadHelpPagesList } from './useLoadHelpPagesList';
|
||||
|
||||
export function Help(): JSX.Element {
|
||||
const items = useLoadHelpPagesList();
|
||||
return (
|
||||
<Grid container spacing={2}>
|
||||
{items.map((item, index) => (
|
||||
<Grid key={index} item xs={12} sm={6} md={4}>
|
||||
<HelpWebsiteItem item={item} />
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
38
src/pages/Help/useLoadHelpPagesList.ts
Normal file
38
src/pages/Help/useLoadHelpPagesList.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* eslint-disable unicorn/no-array-callback-reference */
|
||||
import uniqBy from 'lodash/uniqBy';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { LastArrayElement } from 'type-fest';
|
||||
import helpPages from './helpPages.json';
|
||||
|
||||
function makeFallbackUrlsArray(item: LastArrayElement<typeof helpPages.default>): Omit<LastArrayElement<typeof helpPages.default>, 'fallbackUrls'> & { fallbackUrls: string[] } {
|
||||
return { ...item, fallbackUrls: item?.fallbackUrls?.split(' ') ?? [] };
|
||||
}
|
||||
|
||||
export function useLoadHelpPagesList() {
|
||||
const [items, setItems] = useState(helpPages.default.map(makeFallbackUrlsArray));
|
||||
useEffect(() => {
|
||||
const loadMoreItems = async () => {
|
||||
try {
|
||||
const responses = await Promise.all(
|
||||
helpPages.onlineSources.map(async source => {
|
||||
try {
|
||||
const data = await fetch(source).then(async response => await (response.json() as Promise<typeof helpPages.default>));
|
||||
return data.map(makeFallbackUrlsArray);
|
||||
} catch (error) {
|
||||
await window.service.native.log('error', `Help page Failed to load online source: ${source} ${(error as Error).message}`);
|
||||
return [];
|
||||
}
|
||||
}),
|
||||
);
|
||||
const newItems = responses.flat();
|
||||
setItems(currentItems => uniqBy([...currentItems, ...newItems], 'url'));
|
||||
} catch (error) {
|
||||
console.error('Failed to load online sources:', error);
|
||||
}
|
||||
};
|
||||
|
||||
void loadMoreItems();
|
||||
}, []);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
|
||||
/* eslint-disable @typescript-eslint/promise-function-async */
|
||||
import { lazy } from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styled, { DefaultTheme } from 'styled-components';
|
||||
import { DefaultTheme, styled } from 'styled-components';
|
||||
import is, { isNot } from 'typescript-styled-is';
|
||||
import { Route, Switch } from 'wouter';
|
||||
|
||||
|
|
@ -13,6 +12,7 @@ import { WindowNames } from '@services/windows/WindowProperties';
|
|||
import FindInPage from '../../components/FindInPage';
|
||||
import { SideBar } from '../../components/Sidebar';
|
||||
import { Guide } from '../Guide';
|
||||
import { Help } from '../Help';
|
||||
import { WikiBackground } from '../WikiBackground';
|
||||
import { useInitialPage } from './useInitialPage';
|
||||
|
||||
|
|
@ -79,6 +79,7 @@ export default function Main(): JSX.Element {
|
|||
<Switch>
|
||||
<Route path={`/${WindowNames.main}/${PageType.wiki}/:id/`} component={WikiBackground} />
|
||||
<Route path={`/${WindowNames.main}/${PageType.guide}/`} component={Guide} />
|
||||
<Route path={`/${WindowNames.main}/${PageType.help}/`} component={Help} />
|
||||
<Route path={`/${WindowNames.main}`} component={Guide} />
|
||||
<Route component={Guide} />
|
||||
</Switch>
|
||||
|
|
|
|||
|
|
@ -4,11 +4,18 @@ import { IPage, PageType } from './interface';
|
|||
* Add React component route for build-in pages in `src/pages/Main/index.tsx`
|
||||
*/
|
||||
export const defaultBuildInPages: Record<string, IPage> = {
|
||||
help: {
|
||||
type: PageType.help,
|
||||
id: PageType.help,
|
||||
active: false,
|
||||
hide: false,
|
||||
order: 1,
|
||||
},
|
||||
guide: {
|
||||
type: PageType.guide,
|
||||
id: PageType.guide,
|
||||
active: false,
|
||||
hide: false,
|
||||
order: 0,
|
||||
order: 2,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import AccountTreeIcon from '@mui/icons-material/AccountTree';
|
||||
import HelpIcon from '@mui/icons-material/Help';
|
||||
import InfoIcon from '@mui/icons-material/Info';
|
||||
import { PageType } from '@services/pages/interface';
|
||||
|
||||
|
|
@ -8,6 +8,9 @@ export function getBuildInPageIcon(pageType: PageType): JSX.Element {
|
|||
// this won't happened, because wiki page is not a build-in page
|
||||
return <div>Wiki</div>;
|
||||
}
|
||||
case PageType.help: {
|
||||
return <HelpIcon />;
|
||||
}
|
||||
case PageType.guide: {
|
||||
return <InfoIcon />;
|
||||
}
|
||||
|
|
@ -6,6 +6,9 @@ export function getBuildInPageName(pageType: PageType, t: TFunction) {
|
|||
case PageType.wiki: {
|
||||
return t('Menu.Wiki');
|
||||
}
|
||||
case PageType.help: {
|
||||
return t('WorkspaceSelector.Help');
|
||||
}
|
||||
case PageType.guide: {
|
||||
return t('WorkspaceSelector.Guide');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ export enum PageType {
|
|||
* Default empty page, have some user guide and new user settings.
|
||||
*/
|
||||
guide = 'guide',
|
||||
/**
|
||||
* Show list of available help resources to learn TiddlyWiki.
|
||||
*/
|
||||
help = 'help',
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue