mirror of
https://github.com/docmost/docmost.git
synced 2025-11-16 19:41:09 +10:00
feat: add page stats to page menu (#876)
This commit is contained in:
@ -24,6 +24,7 @@
|
||||
"@mantine/spotlight": "^7.17.0",
|
||||
"@tabler/icons-react": "^3.22.0",
|
||||
"@tanstack/react-query": "^5.61.4",
|
||||
"@tiptap/extension-character-count": "^2.11.5",
|
||||
"axios": "^1.7.9",
|
||||
"clsx": "^2.1.1",
|
||||
"emoji-mart": "^5.6.0",
|
||||
|
||||
@ -346,5 +346,10 @@
|
||||
"Space deleted successfully": "Space deleted successfully",
|
||||
"Members added successfully": "Members added successfully",
|
||||
"Member removed successfully": "Member removed successfully",
|
||||
"Member role updated successfully": "Member role updated successfully"
|
||||
"Member role updated successfully": "Member role updated successfully",
|
||||
"Created by: <b>{{creatorName}}</b>": "Created by: <b>{{creatorName}}</b>",
|
||||
"Created at: {{time}}": "Created at: {{time}}",
|
||||
"Edited by {{name}} {{time}}": "Edited by {{name}} {{time}}",
|
||||
"Word count: {{wordCount}}": "Word count: {{wordCount}}",
|
||||
"Character count: {{characterCount}}": "Character count: {{characterCount}}"
|
||||
}
|
||||
|
||||
@ -71,6 +71,7 @@ import MentionView from "@/features/editor/components/mention/mention-view.tsx";
|
||||
import i18n from "@/i18n.ts";
|
||||
import { MarkdownClipboard } from "@/features/editor/extensions/markdown-clipboard.ts";
|
||||
import EmojiCommand from "./emoji-command";
|
||||
import { CharacterCount } from "@tiptap/extension-character-count";
|
||||
|
||||
const lowlight = createLowlight(common);
|
||||
lowlight.register("mermaid", plaintext);
|
||||
@ -211,6 +212,7 @@ export const mainExtensions = [
|
||||
MarkdownClipboard.configure({
|
||||
transformPastedText: true,
|
||||
}),
|
||||
CharacterCount
|
||||
] as any;
|
||||
|
||||
type CollabExtensions = (provider: HocuspocusProvider, user: IUser) => any[];
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ActionIcon, Group, Menu, Tooltip } from "@mantine/core";
|
||||
import { ActionIcon, Group, Menu, Text, Tooltip } from "@mantine/core";
|
||||
import {
|
||||
IconArrowsHorizontal,
|
||||
IconDots,
|
||||
@ -24,9 +24,13 @@ import { extractPageSlugId } from "@/lib";
|
||||
import { treeApiAtom } from "@/features/page/tree/atoms/tree-api-atom.ts";
|
||||
import { useDeletePageModal } from "@/features/page/hooks/use-delete-page-modal.tsx";
|
||||
import { PageWidthToggle } from "@/features/user/components/page-width-pref.tsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import ExportModal from "@/components/common/export-modal";
|
||||
import { yjsConnectionStatusAtom } from "@/features/editor/atoms/editor-atoms.ts";
|
||||
import {
|
||||
pageEditorAtom,
|
||||
yjsConnectionStatusAtom,
|
||||
} from "@/features/editor/atoms/editor-atoms.ts";
|
||||
import { formattedDate, timeAgo } from "@/lib/time.ts";
|
||||
|
||||
interface PageHeaderMenuProps {
|
||||
readOnly?: boolean;
|
||||
@ -79,6 +83,7 @@ function PageActionMenu({ readOnly }: PageActionMenuProps) {
|
||||
const [tree] = useAtom(treeApiAtom);
|
||||
const [exportOpened, { open: openExportModal, close: closeExportModal }] =
|
||||
useDisclosure(false);
|
||||
const [pageEditor] = useAtom(pageEditorAtom);
|
||||
|
||||
const handleCopyLink = () => {
|
||||
const pageUrl =
|
||||
@ -108,7 +113,7 @@ function PageActionMenu({ readOnly }: PageActionMenuProps) {
|
||||
shadow="xl"
|
||||
position="bottom-end"
|
||||
offset={20}
|
||||
width={200}
|
||||
width={230}
|
||||
withArrow
|
||||
arrowPosition="center"
|
||||
>
|
||||
@ -168,6 +173,41 @@ function PageActionMenu({ readOnly }: PageActionMenuProps) {
|
||||
</Menu.Item>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Menu.Divider />
|
||||
|
||||
<>
|
||||
<Group px="sm" wrap="nowrap" style={{ cursor: "pointer" }}>
|
||||
<Tooltip
|
||||
label={t("Edited by {{name}} {{time}}", {
|
||||
name: page.lastUpdatedBy.name,
|
||||
time: timeAgo(page.updatedAt),
|
||||
})}
|
||||
position="left-start"
|
||||
>
|
||||
<div>
|
||||
<Text size="xs" c="dimmed" truncate="end">
|
||||
{t("Word count: {{wordCount}}", {
|
||||
wordCount: pageEditor?.storage?.characterCount?.words(),
|
||||
})}
|
||||
</Text>
|
||||
|
||||
<Text size="xs" c="dimmed" lineClamp={1}>
|
||||
<Trans
|
||||
defaults="Created by: <b>{{creatorName}}</b>"
|
||||
values={{ creatorName: page?.creator?.name }}
|
||||
components={{ b: <Text span fw={500} /> }}
|
||||
/>
|
||||
</Text>
|
||||
<Text size="xs" c="dimmed" truncate="end">
|
||||
{t("Created at: {{time}}", {
|
||||
time: formattedDate(page.createdAt),
|
||||
})}
|
||||
</Text>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Group>
|
||||
</>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
|
||||
|
||||
@ -12,16 +12,28 @@ export interface IPage {
|
||||
spaceId: string;
|
||||
workspaceId: string;
|
||||
isLocked: boolean;
|
||||
isPublic: boolean;
|
||||
lastModifiedById: Date;
|
||||
lastUpdatedById: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
deletedAt: Date;
|
||||
position: string;
|
||||
hasChildren: boolean;
|
||||
creator: ICreator;
|
||||
lastUpdatedBy: ILastUpdatedBy;
|
||||
space: Partial<ISpace>;
|
||||
}
|
||||
|
||||
interface ICreator {
|
||||
id: string;
|
||||
name: string;
|
||||
avatarUrl: string;
|
||||
}
|
||||
interface ILastUpdatedBy {
|
||||
id: string;
|
||||
name: string;
|
||||
avatarUrl: string;
|
||||
}
|
||||
|
||||
export interface IMovePage {
|
||||
pageId: string;
|
||||
position?: string;
|
||||
|
||||
Reference in New Issue
Block a user