Skip to content

Commit

Permalink
updates and fixes
Browse files Browse the repository at this point in the history
* seo friendly urls
* custom client serve-static module
* database fixes
* fix recent pages
* other fixes
  • Loading branch information
Philipinho committed May 18, 2024
1 parent eefe63d commit 9c7c2f1
Show file tree
Hide file tree
Showing 102 changed files with 897 additions and 512 deletions.
5 changes: 4 additions & 1 deletion apps/client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>docmost</title>
<title>Docmost</title>
</head>
<body>
<div id="root"></div>

<!--window-config-->

<script type="module" src="/src/main.tsx"></script>
</body>
</html>
3 changes: 2 additions & 1 deletion apps/client/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
"version": "0.0.0",
"version": "0.1.0",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
Expand Down Expand Up @@ -31,6 +31,7 @@
"react-arborist": "^3.4.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.13",
"react-helmet-async": "^2.0.5",
"react-router-dom": "^6.22.3",
"socket.io-client": "^4.7.5",
"tippy.js": "^6.3.7",
Expand Down
2 changes: 1 addition & 1 deletion apps/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default function App() {

<Route element={<DashboardLayout />}>
<Route path={"/home"} element={<Home />} />
<Route path={"/p/:pageId"} element={<Page />} />
<Route path={"/p/:slugId/:slug?"} element={<Page />} />
</Route>

<Route path={"/settings"} element={<SettingsLayout />}>
Expand Down
36 changes: 15 additions & 21 deletions apps/client/src/components/layouts/components/breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { IconDots } from "@tabler/icons-react";
import { Link, useParams } from "react-router-dom";
import classes from "./breadcrumb.module.css";
import { SpaceTreeNode } from "@/features/page/tree/types.ts";
import { buildPageSlug } from "@/features/page/page.utils.ts";
import { usePageQuery } from "@/features/page/queries/page-query.ts";

function getTitle(name: string, icon: string) {
if (icon) {
Expand All @@ -27,31 +29,25 @@ export default function Breadcrumb() {
const [breadcrumbNodes, setBreadcrumbNodes] = useState<
SpaceTreeNode[] | null
>(null);
const { pageId } = useParams();
const { slugId } = useParams();
const { data: currentPage } = usePageQuery(slugId);

useEffect(() => {
if (treeData.length) {
const breadcrumb = findBreadcrumbPath(treeData, pageId);
if (treeData?.length > 0 && currentPage) {
const breadcrumb = findBreadcrumbPath(treeData, currentPage.id);
if (breadcrumb) {
setBreadcrumbNodes(breadcrumb);
}
}
}, [pageId, treeData]);

useEffect(() => {
if (treeData.length) {
const breadcrumb = findBreadcrumbPath(treeData, pageId);
if (breadcrumb) setBreadcrumbNodes(breadcrumb);
}
}, [pageId, treeData]);
}, [currentPage?.id, treeData]);

const HiddenNodesTooltipContent = () =>
breadcrumbNodes?.slice(1, -2).map((node) => (
<Button.Group orientation="vertical" key={node.id}>
<Button
justify="start"
component={Link}
to={`/p/${node.id}`}
to={buildPageSlug(node.slugId, node.name)}
variant="default"
style={{ border: "none" }}
>
Expand All @@ -63,16 +59,14 @@ export default function Breadcrumb() {
const getLastNthNode = (n: number) =>
breadcrumbNodes && breadcrumbNodes[breadcrumbNodes.length - n];

// const getTitle = (title: string) => (title?.length > 0 ? title : "untitled");

const getBreadcrumbItems = () => {
if (breadcrumbNodes?.length > 3) {
return [
<Anchor
component={Link}
to={`/p/${breadcrumbNodes[0].id}`}
to={buildPageSlug(breadcrumbNodes[0].slugId, breadcrumbNodes[0].name)}
underline="never"
key={breadcrumbNodes[0].id}
key={breadcrumbNodes[0].slugId}
>
{getTitle(breadcrumbNodes[0].name, breadcrumbNodes[0].icon)}
</Anchor>,
Expand All @@ -94,17 +88,17 @@ export default function Breadcrumb() {
</Popover>,
<Anchor
component={Link}
to={`/p/${getLastNthNode(2)?.id}`}
to={buildPageSlug(getLastNthNode(2)?.slugId, getLastNthNode(2)?.name)}
underline="never"
key={getLastNthNode(2)?.id}
key={getLastNthNode(2)?.slugId}
>
{getTitle(getLastNthNode(2)?.name, getLastNthNode(2)?.icon)}
</Anchor>,
<Anchor
component={Link}
to={`/p/${getLastNthNode(1)?.id}`}
to={buildPageSlug(getLastNthNode(1)?.slugId, getLastNthNode(1)?.name)}
underline="never"
key={getLastNthNode(1)?.id}
key={getLastNthNode(1)?.slugId}
>
{getTitle(getLastNthNode(1)?.name, getLastNthNode(1)?.icon)}
</Anchor>,
Expand All @@ -115,7 +109,7 @@ export default function Breadcrumb() {
return breadcrumbNodes.map((node) => (
<Anchor
component={Link}
to={`/p/${node.id}`}
to={buildPageSlug(node.slugId, node.name)}
underline="never"
key={node.id}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { UserProvider } from "@/features/user/user-provider.tsx";
import Shell from "./shell.tsx";
import { Outlet } from "react-router-dom";
import { Helmet } from "react-helmet-async";

export default function DashboardLayout() {
return (
<UserProvider>
<Shell>
<Helmet>
<title>Home</title>
</Helmet>
<Outlet />
</Shell>
</UserProvider>
Expand Down
29 changes: 23 additions & 6 deletions apps/client/src/components/layouts/dashboard/header.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { ActionIcon, Menu, Button, Tooltip } from "@mantine/core";
import { ActionIcon, Menu, Tooltip } from "@mantine/core";
import {
IconDots,
IconFileInfo,
IconHistory,
IconLink,
IconLock,
IconShare,
IconTrash,
IconMessage,
} from "@tabler/icons-react";
import React from "react";
import useToggleAside from "@/hooks/use-toggle-aside.tsx";
import { useAtom } from "jotai";
import { historyAtoms } from "@/features/page-history/atoms/history-atoms.ts";
import { useClipboard } from "@mantine/hooks";
import { useParams } from "react-router-dom";
import { usePageQuery } from "@/features/page/queries/page-query.ts";
import { buildPageSlug } from "@/features/page/page.utils.ts";
import { notifications } from "@mantine/notifications";

export default function Header() {
const toggleAside = useToggleAside();
Expand Down Expand Up @@ -42,6 +43,16 @@ export default function Header() {

function PageActionMenu() {
const [, setHistoryModalOpen] = useAtom(historyAtoms);
const clipboard = useClipboard({ timeout: 500 });
const { slugId } = useParams();
const { data: page, isLoading, isError } = usePageQuery(slugId);

const handleCopyLink = () => {
const pageLink =
window.location.host + buildPageSlug(page.slugId, page.title);
clipboard.copy(pageLink);
notifications.show({ message: "Link copied" });
};

const openHistoryModal = () => {
setHistoryModalOpen(true);
Expand All @@ -63,20 +74,26 @@ function PageActionMenu() {
</Menu.Target>

<Menu.Dropdown>
<Menu.Item leftSection={<IconLink size={16} stroke={2} />}>
<Menu.Item
leftSection={<IconLink size={16} stroke={2} />}
onClick={handleCopyLink}
>
Copy link
</Menu.Item>
<Menu.Divider />
<Menu.Item
leftSection={<IconHistory size={16} stroke={2} />}
onClick={openHistoryModal}
>
Page history
</Menu.Item>

{/*
<Menu.Divider />
<Menu.Item leftSection={<IconTrash size={16} stroke={2} />}>
Delete
</Menu.Item>
*/}
</Menu.Dropdown>
</Menu>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { UserProvider } from "@/features/user/user-provider.tsx";
import { Outlet } from "react-router-dom";
import SettingsShell from "@/components/layouts/settings/settings-shell.tsx";
import { Helmet } from "react-helmet-async";

export default function SettingsLayout() {
return (
<UserProvider>
<SettingsShell>
<Helmet>
<title>Settings</title>
</Helmet>
<Outlet />
</SettingsShell>
</UserProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function InviteSignUpForm() {
<Container size={420} my={40} className={classes.container}>
<Box p="xl" mt={200}>
<Title order={2} ta="center" fw={500} mb="md">
Complete your signup
Join the workspace
</Title>

<Stack align="stretch" justify="center" gap="xl">
Expand Down
97 changes: 97 additions & 0 deletions apps/client/src/features/auth/components/setup-workspace-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import * as React from "react";
import * as z from "zod";

import { useForm, zodResolver } from "@mantine/form";
import {
Container,
Title,
TextInput,
Button,
PasswordInput,
Box,
} from "@mantine/core";
import { ISetupWorkspace } from "@/features/auth/types/auth.types";
import useAuth from "@/features/auth/hooks/use-auth";
import classes from "@/features/auth/components/auth.module.css";

const formSchema = z.object({
workspaceName: z.string().min(2).max(60),
name: z.string().min(2).max(60),
email: z
.string()
.min(1, { message: "email is required" })
.email({ message: "Invalid email address" }),
password: z.string().min(8),
});

export function SetupWorkspaceForm() {
const { setupWorkspace, isLoading } = useAuth();
// useRedirectIfAuthenticated();

const form = useForm<ISetupWorkspace>({
validate: zodResolver(formSchema),
initialValues: {
workspaceName: "",
name: "",
email: "",
password: "",
},
});

async function onSubmit(data: ISetupWorkspace) {
await setupWorkspace(data);
}

return (
<Container size={420} my={40} className={classes.container}>
<Box p="xl" mt={200}>
<Title order={2} ta="center" fw={500} mb="md">
Create workspace
</Title>

<form onSubmit={form.onSubmit(onSubmit)}>
<TextInput
id="workspaceName"
type="text"
label="Workspace Name"
placeholder="e.g ACME Inc"
variant="filled"
mt="md"
{...form.getInputProps("workspaceName")}
/>

<TextInput
id="name"
type="text"
label="Your Name"
placeholder="enter your full name"
variant="filled"
mt="md"
{...form.getInputProps("name")}
/>

<TextInput
id="email"
type="email"
label="Your Email"
placeholder="[email protected]"
variant="filled"
mt="md"
{...form.getInputProps("email")}
/>

<PasswordInput
label="Password"
placeholder="Enter a strong password"
variant="filled"
mt="md"
{...form.getInputProps("password")}
/>
<Button type="submit" fullWidth mt="xl" loading={isLoading}>
Setup workspace
</Button>
</form>
</Box>
</Container>
);
}
Loading

0 comments on commit 9c7c2f1

Please sign in to comment.