mirror of https://github.com/fantasticit/think.git
Merge pull request #18 from fantasticit/feat/share
This commit is contained in:
commit
8bc7cb5665
|
@ -1,7 +1,20 @@
|
||||||
import React, { useMemo, useEffect } from 'react';
|
import React, { useMemo, useEffect } from 'react';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { Layout, Nav, Space, Button, Typography, Skeleton, Input, Popover, Modal, BackTop } from '@douyinfe/semi-ui';
|
import {
|
||||||
|
Layout,
|
||||||
|
Nav,
|
||||||
|
Space,
|
||||||
|
Button,
|
||||||
|
Typography,
|
||||||
|
Skeleton,
|
||||||
|
Input,
|
||||||
|
Popover,
|
||||||
|
Modal,
|
||||||
|
Breadcrumb,
|
||||||
|
BackTop,
|
||||||
|
} from '@douyinfe/semi-ui';
|
||||||
import { IconArticle } from '@douyinfe/semi-icons';
|
import { IconArticle } from '@douyinfe/semi-icons';
|
||||||
|
import Link from 'next/link';
|
||||||
import { Seo } from 'components/seo';
|
import { Seo } from 'components/seo';
|
||||||
import { LogoImage, LogoText } from 'components/logo';
|
import { LogoImage, LogoText } from 'components/logo';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
|
@ -91,9 +104,14 @@ export const DocumentPublicReader: React.FC<IProps> = ({ documentId, hideLogo =
|
||||||
<Skeleton active placeholder={<Skeleton.Title style={{ width: 80, marginBottom: 8 }} />} loading={true} />
|
<Skeleton active placeholder={<Skeleton.Title style={{ width: 80, marginBottom: 8 }} />} loading={true} />
|
||||||
}
|
}
|
||||||
normalContent={() => (
|
normalContent={() => (
|
||||||
<Text strong ellipsis={{ showTooltip: true }} style={{ width: ~~(windowWidth / 4) }}>
|
<Breadcrumb>
|
||||||
{data.title}
|
<Breadcrumb.Item>
|
||||||
</Text>
|
<Link href="/share/wiki/[wikiId]" as={`/share/wiki/${data.wikiId}`}>
|
||||||
|
<a>{data?.wiki?.name}</a>
|
||||||
|
</Link>
|
||||||
|
</Breadcrumb.Item>
|
||||||
|
<Breadcrumb.Item>{data.title}</Breadcrumb.Item>
|
||||||
|
</Breadcrumb>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Nav>
|
</Nav>
|
||||||
|
|
|
@ -49,6 +49,25 @@ export const DocumentShare: React.FC<IProps> = ({ documentId, render }) => {
|
||||||
onCancel={() => toggleVisible(false)}
|
onCancel={() => toggleVisible(false)}
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
style={{ maxWidth: '96vw' }}
|
style={{ maxWidth: '96vw' }}
|
||||||
|
footer={
|
||||||
|
<>
|
||||||
|
<Button onClick={() => toggleVisible(false)}>取消</Button>
|
||||||
|
<Button theme="solid" type={isPublic ? 'danger' : 'primary'} onClick={handleOk}>
|
||||||
|
{isPublic ? '关闭分享' : '开启分享'}
|
||||||
|
</Button>
|
||||||
|
{isPublic && (
|
||||||
|
<Button
|
||||||
|
theme="solid"
|
||||||
|
type="primary"
|
||||||
|
onClick={() => {
|
||||||
|
window.open(shareUrl, '_blank');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
查看文档
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<DataRender
|
<DataRender
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|
|
@ -14,9 +14,18 @@ interface IProps {
|
||||||
};
|
};
|
||||||
isActive?: boolean;
|
isActive?: boolean;
|
||||||
hoverable?: boolean;
|
hoverable?: boolean;
|
||||||
|
openNewTab?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NavItem: React.FC<IProps> = ({ icon, text, rightNode, href, isActive = false, hoverable = true }) => {
|
export const NavItem: React.FC<IProps> = ({
|
||||||
|
icon,
|
||||||
|
text,
|
||||||
|
rightNode,
|
||||||
|
href,
|
||||||
|
isActive = false,
|
||||||
|
hoverable = true,
|
||||||
|
openNewTab = false,
|
||||||
|
}) => {
|
||||||
const right = rightNode ? <span className={styles.rightWrap}>{rightNode}</span> : null;
|
const right = rightNode ? <span className={styles.rightWrap}>{rightNode}</span> : null;
|
||||||
const content = (
|
const content = (
|
||||||
<>
|
<>
|
||||||
|
@ -32,7 +41,9 @@ export const NavItem: React.FC<IProps> = ({ icon, text, rightNode, href, isActiv
|
||||||
>
|
>
|
||||||
{href ? (
|
{href ? (
|
||||||
<Link href={href as UrlObject}>
|
<Link href={href as UrlObject}>
|
||||||
<a className={styles.navItem}>{content}</a>
|
<a className={styles.navItem} target={openNewTab ? '_blank' : '_self'}>
|
||||||
|
{content}
|
||||||
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<div className={styles.navItem}>{content}</div>
|
<div className={styles.navItem}>{content}</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Avatar, Button, Typography, Skeleton } from '@douyinfe/semi-ui';
|
import { Avatar, Button, Typography, Skeleton, Tooltip } from '@douyinfe/semi-ui';
|
||||||
import { IconPlus } from '@douyinfe/semi-icons';
|
import { IconPlus } from '@douyinfe/semi-icons';
|
||||||
import { useWikiDetail, useWikiTocs } from 'data/wiki';
|
import { useWikiDetail, useWikiTocs } from 'data/wiki';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
|
@ -13,6 +13,7 @@ import { EventEmitter } from 'helpers/event-emitter';
|
||||||
import { NavItem } from './NavItem';
|
import { NavItem } from './NavItem';
|
||||||
import { Tree } from './tree';
|
import { Tree } from './tree';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
import { isPublicWiki } from '@think/domains';
|
||||||
|
|
||||||
const em = new EventEmitter();
|
const em = new EventEmitter();
|
||||||
const EVENT_KEY = 'REFRESH_TOCS';
|
const EVENT_KEY = 'REFRESH_TOCS';
|
||||||
|
@ -127,6 +128,45 @@ export const WikiTocs: React.FC<IProps> = ({
|
||||||
isActive={pathname === '/wiki/[wikiId]/setting'}
|
isActive={pathname === '/wiki/[wikiId]/setting'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<DataRender
|
||||||
|
loading={wikiLoading}
|
||||||
|
loadingContent={
|
||||||
|
<NavItem
|
||||||
|
icon={
|
||||||
|
<Skeleton.Avatar
|
||||||
|
size="small"
|
||||||
|
style={{
|
||||||
|
marginRight: 8,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
borderRadius: 4,
|
||||||
|
}}
|
||||||
|
></Skeleton.Avatar>
|
||||||
|
}
|
||||||
|
text={<Skeleton.Title style={{ width: 120 }} />}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
error={wikiError}
|
||||||
|
normalContent={() =>
|
||||||
|
isPublicWiki(wiki.status) ? (
|
||||||
|
<NavItem
|
||||||
|
icon={<IconOverview />}
|
||||||
|
text={
|
||||||
|
<Tooltip content="该知识库已公开,点我查看" position="right">
|
||||||
|
公开地址
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
href={{
|
||||||
|
pathname: `/share/wiki/[wikiId]`,
|
||||||
|
query: { wikiId },
|
||||||
|
}}
|
||||||
|
isActive={pathname === '/share/wiki/[wikiId]'}
|
||||||
|
openNewTab
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<DataRender
|
<DataRender
|
||||||
loading={wikiLoading}
|
loading={wikiLoading}
|
||||||
loadingContent={
|
loadingContent={
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { IUser, IDocument } from '@think/domains';
|
import type { IUser, IDocument, IWiki } from '@think/domains';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { useState, useCallback, useEffect } from 'react';
|
import { useState, useCallback, useEffect } from 'react';
|
||||||
import { useAsyncLoading } from 'hooks/use-async-loading';
|
import { useAsyncLoading } from 'hooks/use-async-loading';
|
||||||
|
@ -128,7 +128,7 @@ export const useStaredDocuments = () => {
|
||||||
*/
|
*/
|
||||||
export const usePublicDocument = (documentId: string) => {
|
export const usePublicDocument = (documentId: string) => {
|
||||||
const [fetch] = useAsyncLoading(getPublicDocumentDetail);
|
const [fetch] = useAsyncLoading(getPublicDocumentDetail);
|
||||||
const [document, setDocument] = useState<IDocument | null>(null);
|
const [document, setDocument] = useState<(IDocument & { createUse: IUser; wiki: IWiki }) | null>(null);
|
||||||
const [error, setError] = useState<(Error & { statusCode?: number }) | null>(null);
|
const [error, setError] = useState<(Error & { statusCode?: number }) | null>(null);
|
||||||
const loading = !document && !error;
|
const loading = !document && !error;
|
||||||
|
|
||||||
|
|
|
@ -552,8 +552,9 @@ export class DocumentService {
|
||||||
await this.viewService.create({ userId: 'public', documentId, userAgent });
|
await this.viewService.create({ userId: 'public', documentId, userAgent });
|
||||||
const views = await this.viewService.getDocumentTotalViews(documentId);
|
const views = await this.viewService.getDocumentTotalViews(documentId);
|
||||||
const createUser = await this.userService.findById(document.createUserId);
|
const createUser = await this.userService.findById(document.createUserId);
|
||||||
|
const wiki = await this.wikiService.getPublicWikiDetail(document.wikiId);
|
||||||
|
|
||||||
return { ...document, views, createUser };
|
return { ...document, views, wiki, createUser };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue