diff --git a/apps/web/.eslintrc.js b/apps/web/.eslintrc.js
index b88cc6af..7bdf09b7 100644
--- a/apps/web/.eslintrc.js
+++ b/apps/web/.eslintrc.js
@@ -93,7 +93,7 @@ module.exports = {
position: 'after',
},
{
- pattern: '@hooks/**',
+ pattern: 'hooks/**',
group: 'internal',
position: 'after',
},
diff --git a/apps/web/src/components/Auth/SignupForm.tsx b/apps/web/src/components/Auth/SignupForm.tsx
index 321bea56..9e6d3cde 100644
--- a/apps/web/src/components/Auth/SignupForm.tsx
+++ b/apps/web/src/components/Auth/SignupForm.tsx
@@ -4,6 +4,7 @@ import { useForm } from 'react-hook-form';
import toast from 'react-hot-toast';
import { Flex, Box, Button, Text, Field, InputText } from '@wraft/ui';
import { BrandLogoIcon } from '@wraft/icon';
+import styled from '@emotion/styled';
import Link from 'common/NavLink';
import ErrorMessages from 'common/ErrorMessages';
@@ -12,6 +13,89 @@ import { postAPI } from 'utils/models';
import WaitlistPrompt from './WaitlistPrompt';
+const NameFields = styled(Flex)`
+ display: flex;
+ flex-direction: row;
+ gap: 16px;
+ margin-bottom: 24px;
+
+ @media (max-width: 768px) {
+ flex-direction: column;
+ }
+`;
+
+const ResponsiveLogo = styled(BrandLogoIcon)`
+ width: 7rem;
+ height: 3rem;
+
+ @media (max-width: 768px) {
+ width: 5rem;
+ height: 2rem;
+ }
+
+ @media (max-width: 480px) {
+ width: 5rem;
+ height: 1.8rem;
+ }
+`;
+
+const LogoWrapper = styled(Box)`
+ position: absolute;
+ top: 80px;
+ left: 80px;
+
+ @media (max-width: 1024px) {
+ top: 60px;
+ left: 40px;
+ }
+
+ @media (max-width: 768px) {
+ position: relative;
+ top: 0;
+ left: 0;
+ display: flex;
+ justify-content: flex-start;
+ width: 100%;
+ padding-left: 16px;
+ margin-bottom: 24px;
+ }
+
+ @media (max-width: 480px) {
+ padding-left: 12px;
+ margin-bottom: 20px;
+ }
+`;
+
+const FormCard = styled(Flex)`
+ width: 500px;
+ flex-direction: column;
+ background: white;
+ border-radius: 12px;
+ padding: 32px;
+
+ @media (max-width: 768px) {
+ width: 100%;
+ max-width: 90%;
+ }
+
+ @media (max-width: 480px) {
+ max-width: 95%;
+ padding: 20px;
+ }
+`;
+
+const PageWrapper = styled(Flex)`
+ justify-content: center;
+ align-items: flex-start;
+ padding: 6rem;
+
+ @media (max-width: 768px) {
+ flex-direction: column;
+ align-items: center;
+ padding: 2rem 1rem;
+ }
+`;
+
const SignupForm = () => {
const {
register,
@@ -21,6 +105,7 @@ const SignupForm = () => {
mode: 'onSubmit',
resolver: zodResolver(SignUpSchema),
});
+
const [showSuccess, setShowSuccess] = useState(false);
const homePageUrl = process.env.homePageUrl || '/';
@@ -48,24 +133,22 @@ const SignupForm = () => {
{showSuccess ? (
) : (
-
-
+
+
-
+
-
-
+
+
+
Join Wraft
+
-
+
{
/>
-
-
+
+
+
{
+
Already joined?
@@ -113,8 +198,8 @@ const SignupForm = () => {
Privacy Policy.
-
-
+
+
)}
>
);
diff --git a/apps/web/src/components/DocumentView/DocumentSidebar/ContentInfoBlock.tsx b/apps/web/src/components/DocumentView/DocumentSidebar/ContentInfoBlock.tsx
index 50464a32..be725db2 100644
--- a/apps/web/src/components/DocumentView/DocumentSidebar/ContentInfoBlock.tsx
+++ b/apps/web/src/components/DocumentView/DocumentSidebar/ContentInfoBlock.tsx
@@ -142,7 +142,10 @@ export const EditMenus = ({ id, nextState }: EditMenuProps) => {
/>
-
+ setMailPopupOpen(false)}>
<>
{isMailPopupOpen && (
diff --git a/apps/web/src/components/ImportTemplate/ImporterWrapper.tsx b/apps/web/src/components/ImportTemplate/ImporterWrapper.tsx
index 4ca244d0..23b09022 100644
--- a/apps/web/src/components/ImportTemplate/ImporterWrapper.tsx
+++ b/apps/web/src/components/ImportTemplate/ImporterWrapper.tsx
@@ -77,7 +77,6 @@ function ImporterApp() {
useState(defaultActionState);
const [imported, setImported] = useState();
-
const [errors, setErrors] = useState([]);
const handleNext = () => {
@@ -88,11 +87,10 @@ function ImporterApp() {
/*
* Initiate Import process
- * @param id string
- * import templates from uploaded template aset
+ * import templates from uploaded template asset
*/
- const importNow = (id: string, _onDone?: any) => {
+ const importNow = () => {
if (!formData) {
handleNext();
setActionState({ state: ActionState.COMPLETED });
@@ -105,13 +103,18 @@ function ImporterApp() {
});
postAPI(`global_asset/import`, formData)
.then((res: ImportedItems) => {
- toast.success(`Successfully imported template: ${id}`);
+ const templateName =
+ res.items?.find((item) => item.item_type === 'data_template')
+ ?.title ||
+ res.items?.[0]?.title ||
+ res.items?.[0]?.name;
+
+ toast.success(`Successfully imported: ${templateName}`);
setImported(res);
handleNext();
setActionState({
state: ActionState.COMPLETED,
});
- _onDone && _onDone(res);
})
.catch((error: any) => {
setErrors(error);
@@ -216,7 +219,6 @@ function ImporterApp() {
/>
)}
-
{currentStep === 2 && (
= ({
const handleViewAll = () => {
router.push('/notifications');
};
-
const handleSettingsClick = () => {
- router.push('/manage/workspace/notification-settings');
+ router.push({
+ pathname: '/manage/workspace/notification-settings',
+ query: { from: 'notifications' },
+ });
};
return (
diff --git a/apps/web/src/components/Notification/NotificationList.tsx b/apps/web/src/components/Notification/NotificationList.tsx
index 03c7326c..6917fd1b 100644
--- a/apps/web/src/components/Notification/NotificationList.tsx
+++ b/apps/web/src/components/Notification/NotificationList.tsx
@@ -3,7 +3,7 @@ import { useRouter } from 'next/router';
import { Avatar, Pagination, Box, Text, Flex } from '@wraft/ui';
import styled from '@xstyled/emotion';
-import useNotifications from '@hooks/useNotifications';
+import useNotifications from 'hooks/useNotifications';
import { TimeAgo } from 'common/Atoms';
import {
diff --git a/apps/web/src/components/Sidebar/Header.tsx b/apps/web/src/components/Sidebar/Header.tsx
index a3c42316..4abaa18e 100644
--- a/apps/web/src/components/Sidebar/Header.tsx
+++ b/apps/web/src/components/Sidebar/Header.tsx
@@ -3,9 +3,10 @@ import { useRouter } from 'next/router';
import NavLink from 'next/link';
import { Button, DropdownMenu, Box, Flex, Text, Modal } from '@wraft/ui';
import toast from 'react-hot-toast';
-import { CaretDown, Gear, Plus } from '@phosphor-icons/react';
+import { CaretDownIcon, GearIcon, PlusIcon } from '@phosphor-icons/react';
import NotificationDropdown from 'components/Notification/NotificationDropdown';
+import { useNotificationSidebarMode } from 'hooks/useNotificationSidebarMode';
import DefaultAvatar from 'common/DefaultAvatar';
import { IconFrame } from 'common/Atoms';
import { useAuth } from 'contexts/AuthContext';
@@ -20,6 +21,7 @@ const Header = ({
}) => {
const [isOpen, setIsOpen] = useState(false);
const [createdId, setCreatedId] = useState();
+ const { clearNotificationSidebarMode } = useNotificationSidebarMode();
const router = useRouter();
const { organisations, userProfile, login } = useAuth();
@@ -69,7 +71,7 @@ const Header = ({
lines={1}>
{userProfile?.currentOrganisation?.name}
-
+
)}
@@ -102,7 +104,12 @@ const Header = ({
-
+
>
)}
@@ -136,7 +143,7 @@ const Header = ({
@@ -152,7 +159,7 @@ const Header = ({
size="xs"
onClick={toggleCreateDocument}>
-
+
diff --git a/apps/web/src/components/Template/TemplateForm.tsx b/apps/web/src/components/Template/TemplateForm.tsx
index 8aba0021..ab46a2df 100644
--- a/apps/web/src/components/Template/TemplateForm.tsx
+++ b/apps/web/src/components/Template/TemplateForm.tsx
@@ -388,7 +388,7 @@ const TemplateEditor = () => {
/>
- {selectedVariant && selectedVariant.fields && !templateId && (
+ {selectedVariant && selectedVariant.fields && (
{
hint="The variant type cannot be modified once saved. Please select the correct one."
required
error={errors?.variant?.message}>
- item && item.name}
- name={name}
- placeholder="Search Variant"
- minChars={0}
- value={value}
- onChange={(variant: any) => {
- if (variant?.id) {
- onChange(variant);
- fetchContentTypeDetails(variant?.id);
- }
- }}
- renderItem={(item: any) => (
-
- {item.name}
-
- )}
- search={onSearchVariants}
- />
+ {templateId ? (
+
+ ) : (
+ item && item.name}
+ name={name}
+ placeholder="Search Variant"
+ minChars={0}
+ value={value}
+ onChange={(variant: any) => {
+ if (variant?.id) {
+ onChange(variant);
+ fetchContentTypeDetails(variant?.id);
+ }
+ }}
+ renderItem={(item: any) => (
+
+ {item.name}
+
+ )}
+ search={onSearchVariants}
+ disabled={!!templateId}
+ />
+ )}
)}
/>
diff --git a/apps/web/src/components/Template/TemplateList.tsx b/apps/web/src/components/Template/TemplateList.tsx
index d7d5835d..0297387f 100644
--- a/apps/web/src/components/Template/TemplateList.tsx
+++ b/apps/web/src/components/Template/TemplateList.tsx
@@ -75,9 +75,6 @@ const columns = ({
{hasPermission('template', 'manage') && (
-
- Edit
-
onCloneTemplete(row.original)}>
Clone
diff --git a/apps/web/src/components/User/ProfileForm.tsx b/apps/web/src/components/User/ProfileForm.tsx
index 2d789c44..82725d25 100644
--- a/apps/web/src/components/User/ProfileForm.tsx
+++ b/apps/web/src/components/User/ProfileForm.tsx
@@ -77,6 +77,15 @@ const EditText = styled(Box)`
transition: opacity 0.2s;
`;
+const StyledDateInput = styled(InputText)`
+ @media (prefers-color-scheme: dark) {
+ &[type="date"] {
+ &::-webkit-calendar-picker-indicator {
+ filter: invert(0.4);
+ }
+
+`;
+
const Form = () => {
const { accessToken } = useAuth();
const [profile, setProfile] = useState();
@@ -219,7 +228,7 @@ const Form = () => {
-
+
diff --git a/apps/web/src/components/Variants/VariantForm.tsx b/apps/web/src/components/Variants/VariantForm.tsx
index 0d97f0d4..ea6ec17a 100644
--- a/apps/web/src/components/Variants/VariantForm.tsx
+++ b/apps/web/src/components/Variants/VariantForm.tsx
@@ -354,9 +354,9 @@ const VariantForm = ({ step = 0, setIsOpen, setRerender }: Props) => {
return false;
};
- const onSearchLayouts = async () => {
+ const onSearchLayouts = async (query: string) => {
try {
- const response: any = await fetchAPI('layouts');
+ const response: any = await fetchAPI(`layouts?name=${query}`);
if (!response || !response.layouts) {
throw new Error('Invalid response structure');
@@ -369,9 +369,9 @@ const VariantForm = ({ step = 0, setIsOpen, setRerender }: Props) => {
}
};
- const onSearchFlows = async () => {
+ const onSearchFlows = async (query: string) => {
try {
- const response: any = await fetchAPI('flows');
+ const response: any = await fetchAPI(`flows?name=${query}`);
if (!response || !response.flows) {
throw new Error('Invalid response structure');
@@ -389,9 +389,9 @@ const VariantForm = ({ step = 0, setIsOpen, setRerender }: Props) => {
}
};
- const onSearchThemes = async () => {
+ const onSearchThemes = async (query: string) => {
try {
- const response: any = await fetchAPI('themes');
+ const response: any = await fetchAPI(`themes?name=${query}`);
if (!response || !response.themes) {
throw new Error('Invalid response structure');
diff --git a/apps/web/src/constants/menuLinks.tsx b/apps/web/src/constants/menuLinks.tsx
index 594d12b6..1f7c4710 100644
--- a/apps/web/src/constants/menuLinks.tsx
+++ b/apps/web/src/constants/menuLinks.tsx
@@ -55,11 +55,6 @@ export const PersonalWorkspaceLinks: menuLinksProps[] = [
path: '/manage/workspace',
permissions: ['workspace.update', 'workspace.delete', 'workspace.invite'],
},
- {
- name: 'Fields',
- path: '/manage/fields',
- permissions: ['workspace.update', 'workspace.delete', 'workspace.invite'],
- },
];
export const workspaceLinks: menuLinksProps[] = [
@@ -171,3 +166,9 @@ export const workspaceMenu: menuLinksProps[] = [
]
: []),
];
+
+export const NOTIFICATION_LINK_NAMES = ['General', 'Notification'];
+
+export const notificationSidebarLinks: menuLinksProps[] = workspaceLinks.filter(
+ (link) => NOTIFICATION_LINK_NAMES.includes(link.name),
+);
diff --git a/apps/web/src/hooks/useNotificationSidebarMode.ts b/apps/web/src/hooks/useNotificationSidebarMode.ts
new file mode 100644
index 00000000..d2b54923
--- /dev/null
+++ b/apps/web/src/hooks/useNotificationSidebarMode.ts
@@ -0,0 +1,55 @@
+import { useEffect, useState } from 'react';
+import { useRouter } from 'next/router';
+
+import {
+ workspaceLinks,
+ PersonalWorkspaceLinks,
+ notificationSidebarLinks,
+} from '@constants/menuLinks';
+
+const NOTIFICATION_MODE_KEY = 'wraft_from_notifications';
+
+export function useNotificationSidebarMode(currentOrgName?: string) {
+ const router = useRouter();
+ const [fromNotification, setFromNotification] = useState(false);
+
+ const enableNotificationMode = () => {
+ sessionStorage.setItem(NOTIFICATION_MODE_KEY, '1');
+ setFromNotification(true);
+ };
+
+ const disableNotificationMode = () => {
+ sessionStorage.removeItem(NOTIFICATION_MODE_KEY);
+ setFromNotification(false);
+ };
+
+ useEffect(() => {
+ if (!router.isReady) return;
+
+ const queryFrom = Array.isArray(router.query.from)
+ ? router.query.from[0]
+ : router.query.from;
+
+ if (queryFrom === 'notifications') {
+ enableNotificationMode();
+ router.replace(router.pathname, undefined, { shallow: true });
+ return;
+ }
+
+ const isFlagSet = sessionStorage.getItem(NOTIFICATION_MODE_KEY) === '1';
+ setFromNotification(isFlagSet);
+ }, [router.isReady, router.query.from]);
+
+ const itemsForSidebar =
+ currentOrgName !== 'Personal'
+ ? workspaceLinks
+ : fromNotification
+ ? notificationSidebarLinks
+ : PersonalWorkspaceLinks;
+
+ return {
+ fromNotification,
+ itemsForSidebar,
+ clearNotificationSidebarMode: disableNotificationMode,
+ };
+}
diff --git a/apps/web/src/pages/manage/workspace/fields.tsx b/apps/web/src/pages/manage/workspace/fields.tsx
index 0b9f6e02..22b43c8f 100644
--- a/apps/web/src/pages/manage/workspace/fields.tsx
+++ b/apps/web/src/pages/manage/workspace/fields.tsx
@@ -1,5 +1,6 @@
-import { FC } from 'react';
+import { FC, useEffect } from 'react';
import Head from 'next/head';
+import router from 'next/router';
import { Flex } from '@wraft/ui';
import { workspaceLinks } from '@constants/menuLinks';
@@ -8,41 +9,55 @@ import ManageSidebar from 'common/ManageSidebar';
import Page from 'common/PageFrame';
import PageHeader from 'common/PageHeader';
import { PageInner } from 'common/Atoms';
+import { useAuth } from 'contexts/AuthContext';
const CompanyForm: FC = () => {
+ const { userProfile } = useAuth();
+ const currentOrg = userProfile?.currentOrganisation?.name;
+
+ useEffect(() => {
+ if (currentOrg === 'Personal') {
+ router.replace('/404');
+ }
+ }, [currentOrg]);
+
+ if (currentOrg === 'Personal') return null;
+
return (
- <>
-
- Manage Organization \ Fields | Wraft
-
-
-
-
+ (currentOrg !== 'Personal' || '') && (
+ <>
+
+ Manage Organization \ Fields | Wraft
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
-
-
-
- >
+
+
+ >
+ )
);
};
diff --git a/apps/web/src/pages/manage/workspace/index.tsx b/apps/web/src/pages/manage/workspace/index.tsx
index 89d5b3df..3deaa9a5 100644
--- a/apps/web/src/pages/manage/workspace/index.tsx
+++ b/apps/web/src/pages/manage/workspace/index.tsx
@@ -6,7 +6,7 @@ import toast from 'react-hot-toast';
import { Input, Label } from 'theme-ui';
import { Box, Field, Flex, InputText, Text, Button, Modal } from '@wraft/ui';
-import { PersonalWorkspaceLinks, workspaceLinks } from '@constants/menuLinks';
+import { useNotificationSidebarMode } from 'hooks/useNotificationSidebarMode';
import ManageSidebar from 'common/ManageSidebar';
import DefaultAvatar from 'common/DefaultAvatar';
import Page from 'common/PageFrame';
@@ -58,6 +58,7 @@ const Index: FC = () => {
const orgId = userProfile?.organisation_id || null;
const currentOrg = userProfile?.currentOrganisation || null;
+ const { itemsForSidebar } = useNotificationSidebarMode(currentOrg?.name);
const [previewSource, setPreviewSource] = useState(
undefined,
@@ -235,13 +236,7 @@ const Index: FC = () => {
-
+
{
setRefresh((prev) => prev + 1);
};
+ useEffect(() => {
+ if (currentOrg === 'Personal') {
+ router.replace('/404');
+ }
+ }, [currentOrg]);
+
+ if (currentOrg === 'Personal') return null;
+
return (
(currentOrg !== 'Personal' || '') && (
<>
diff --git a/apps/web/src/pages/manage/workspace/notification-settings.tsx b/apps/web/src/pages/manage/workspace/notification-settings.tsx
index 8a643112..fcfe9419 100644
--- a/apps/web/src/pages/manage/workspace/notification-settings.tsx
+++ b/apps/web/src/pages/manage/workspace/notification-settings.tsx
@@ -2,14 +2,21 @@ import { FC } from 'react';
import Head from 'next/head';
import { Flex } from '@wraft/ui';
-import { workspaceLinks } from '@constants/menuLinks';
import NotificationSettings from 'components/Notification/NotificationSettings';
+import { useNotificationSidebarMode } from 'hooks/useNotificationSidebarMode';
import Page from 'common/PageFrame';
import PageHeader from 'common/PageHeader';
import ManageSidebar from 'common/ManageSidebar';
import { PageInner } from 'common/Atoms';
+import { useAuth } from 'contexts/AuthContext';
const WorkspaceNotificationSettings: FC = () => {
+ const { userProfile } = useAuth();
+ const currentOrganisation = userProfile?.currentOrganisation;
+ const { itemsForSidebar } = useNotificationSidebarMode(
+ currentOrganisation?.name,
+ );
+
return (
<>
@@ -29,7 +36,7 @@ const WorkspaceNotificationSettings: FC = () => {
/>
-
+
diff --git a/apps/web/src/pages/manage/workspace/permissions.tsx b/apps/web/src/pages/manage/workspace/permissions.tsx
index 291c45cb..bdddf275 100644
--- a/apps/web/src/pages/manage/workspace/permissions.tsx
+++ b/apps/web/src/pages/manage/workspace/permissions.tsx
@@ -1,5 +1,6 @@
-import React, { FC } from 'react';
+import React, { FC, useEffect } from 'react';
import Head from 'next/head';
+import { useRouter } from 'next/router';
import { Flex } from '@wraft/ui';
import { workspaceLinks } from '@constants/menuLinks';
@@ -12,8 +13,19 @@ import { useAuth } from 'contexts/AuthContext';
const Index: FC = () => {
const { userProfile } = useAuth();
+ const router = useRouter();
+ const currentOrg = userProfile?.currentOrganisation?.name;
+
+ useEffect(() => {
+ if (currentOrg === 'Personal') {
+ router.replace('/404');
+ }
+ }, [currentOrg, router]);
+
+ if (currentOrg === 'Personal') return null;
+
return (
- (userProfile?.currentOrganisation?.name !== 'Personal' || '') && (
+ userProfile?.currentOrganisation?.name !== 'Personal' && (
<>
Permission | Wraft
diff --git a/apps/web/src/pages/manage/workspace/roles.tsx b/apps/web/src/pages/manage/workspace/roles.tsx
index 1dd4959e..f55f7106 100644
--- a/apps/web/src/pages/manage/workspace/roles.tsx
+++ b/apps/web/src/pages/manage/workspace/roles.tsx
@@ -1,5 +1,6 @@
-import React, { FC, useState } from 'react';
+import React, { FC, useEffect, useState } from 'react';
import Head from 'next/head';
+import { useRouter } from 'next/router';
import { Spinner } from '@wraft/ui';
import { MagnifyingGlassIcon, PlusIcon } from '@phosphor-icons/react';
import { Button, Flex, Box, InputText, Drawer, useDrawer } from '@wraft/ui';
@@ -22,6 +23,16 @@ const Index: FC = () => {
const { userProfile } = useAuth();
const roleDrawer = useDrawer();
const { hasPermission } = usePermission();
+ const router = useRouter();
+ const currentOrg = userProfile?.currentOrganisation?.name;
+
+ useEffect(() => {
+ if (currentOrg === 'Personal') {
+ router.replace('/404');
+ }
+ }, [currentOrg, router]);
+
+ if (currentOrg === 'Personal') return null;
return (
(userProfile?.currentOrganisation?.name !== 'Personal' || '') && (
diff --git a/apps/web/src/pages/manage/workspace/webhooks/index.tsx b/apps/web/src/pages/manage/workspace/webhooks/index.tsx
index 5423d407..71a2e169 100644
--- a/apps/web/src/pages/manage/workspace/webhooks/index.tsx
+++ b/apps/web/src/pages/manage/workspace/webhooks/index.tsx
@@ -1,5 +1,6 @@
-import React, { useState } from 'react';
+import React, { useEffect, useState } from 'react';
import Head from 'next/head';
+import { useRouter } from 'next/router';
import { Button, Drawer, useDrawer, Flex } from '@wraft/ui';
import { Plus } from '@phosphor-icons/react';
@@ -23,6 +24,8 @@ const WebhooksPage = () => {
const canCreateWebhooks = hasPermission('webhook', 'manage');
const createDrawer = useDrawer();
const editDrawer = useDrawer();
+ const router = useRouter();
+ const currentOrg = userProfile?.currentOrganisation?.name;
const handleCreateSuccess = () => {
setIsCreateDrawerOpen(false);
@@ -42,6 +45,14 @@ const WebhooksPage = () => {
setRefreshKey((prevKey) => prevKey + 1);
};
+ useEffect(() => {
+ if (currentOrg === 'Personal') {
+ router.replace('/404');
+ }
+ }, [currentOrg, router]);
+
+ if (currentOrg === 'Personal') return null;
+
return (
(userProfile?.currentOrganisation?.name !== 'Personal' || '') && (
<>
diff --git a/apps/web/src/schemas/template.ts b/apps/web/src/schemas/template.ts
index 86ed68cd..a94a5ca8 100644
--- a/apps/web/src/schemas/template.ts
+++ b/apps/web/src/schemas/template.ts
@@ -10,6 +10,7 @@ export const TemplateSchema = z.object({
.regex(nameRegex, 'Allows only letters, numbers and spaces'),
variant: z.object({
id: z.string().nonempty({ message: 'Variant is required' }),
+ name: z.string().optional(),
}),
title_template: z.string().optional(),
serialized: z.string().optional(),
diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json
index b7e33534..cb804a90 100644
--- a/apps/web/tsconfig.json
+++ b/apps/web/tsconfig.json
@@ -6,7 +6,7 @@
"paths": {
"common/*": ["components/common/*"],
"@constants/*": ["constants/*"],
- "@hooks/*": ["hooks/*"]
+ "hooks/*": ["hooks/*"]
},
"lib": ["dom", "es2017"],
diff --git a/packages/editor/src/components/editor.tsx b/packages/editor/src/components/editor.tsx
index 9fa4620e..86113b37 100644
--- a/packages/editor/src/components/editor.tsx
+++ b/packages/editor/src/components/editor.tsx
@@ -3,8 +3,8 @@ import { ProseKit } from "prosekit/react";
import { useMemo, useImperativeHandle, forwardRef } from "react";
import { ListDOMSerializer } from "prosekit/extensions/list";
import type { Node } from "@prosekit/pm/model";
-import { markdownFromHTML } from "@helpers/markdown";
import type { ProsemirrorNodeJSON } from "prosemirror-flat-list";
+import { markdownFromHTML } from "@helpers/markdown";
import { migrateDocJSON } from "@helpers/migrate";
import { defineDefaultExtension } from "./extension";
import InlineMenu from "./inline-menu";
@@ -87,10 +87,15 @@ export const Editor = forwardRef(
return (
-
+
+ {!isReadonly && (
+
+
+
+ )}
+
- {!isReadonly && }
{!isReadonly && }
@@ -101,7 +106,7 @@ export const Editor = forwardRef(
-
+ {" "}
);
},
diff --git a/packages/editor/src/components/extension.ts b/packages/editor/src/components/extension.ts
index 30dd6cdf..23cce94a 100644
--- a/packages/editor/src/components/extension.ts
+++ b/packages/editor/src/components/extension.ts
@@ -17,6 +17,7 @@ import { defineYjs } from "prosekit/extensions/yjs";
import type { Awareness } from "y-protocols/awareness";
import type * as Y from "yjs";
import { defineReadonly } from "prosekit/extensions/readonly";
+import { defineCommitViewer } from "prosekit/extensions/commit";
import type { HolderExtension } from "@extensions/holder";
import { defineHolder } from "@extensions/holder";
import { defineFancyParagraph } from "@extensions/paragraph";
@@ -29,7 +30,6 @@ import type { SignatureExtension } from "@extensions/signature";
import { defineSignature } from "@extensions/signature";
import type { PageBreakExtension } from "@extensions/page-break";
import { definePageBreak } from "@extensions/page-break";
-import { defineCommitViewer } from "prosekit/extensions/commit";
import ImageView from "./image-view";
import SignatureView from "./signature-view";
import type { SignersConfig } from "./live-editor";
diff --git a/packages/editor/src/components/live-editor.tsx b/packages/editor/src/components/live-editor.tsx
index e64a5dd1..b0f96762 100644
--- a/packages/editor/src/components/live-editor.tsx
+++ b/packages/editor/src/components/live-editor.tsx
@@ -16,10 +16,10 @@ import { prosemirrorJSONToYXmlFragment } from "y-prosemirror";
import { ListDOMSerializer } from "prosekit/extensions/list";
import type { Node } from "@prosekit/pm/model";
import type { Awareness } from "y-protocols/awareness";
+import type { ProsemirrorNodeJSON } from "prosemirror-flat-list";
import { markdownFromHTML } from "@helpers/markdown";
// import { IndexeddbPersistence } from "y-indexeddb";
import { migrateDocJSON } from "@helpers/migrate";
-import type { ProsemirrorNodeJSON } from "prosemirror-flat-list";
import { getUserColor } from "../lib/utils";
import { PhoenixChannelProvider } from "../lib/y-phoenix-channel";
import { defineCollaborativeExtension } from "./extension";
diff --git a/packages/editor/src/helpers/migrate.ts b/packages/editor/src/helpers/migrate.ts
index aab6230f..6143ca7c 100644
--- a/packages/editor/src/helpers/migrate.ts
+++ b/packages/editor/src/helpers/migrate.ts
@@ -1,5 +1,5 @@
-import type { ListAttrs } from "@extensions/list-item";
import type { ProsemirrorNodeJSON } from "prosemirror-flat-list";
+import type { ListAttrs } from "@extensions/list-item";
function migrateNodes(
nodes: ProsemirrorNodeJSON[],
diff --git a/packages/ui/src/components/Paginate/index.tsx b/packages/ui/src/components/Paginate/index.tsx
index a381ef68..d4a75e9d 100644
--- a/packages/ui/src/components/Paginate/index.tsx
+++ b/packages/ui/src/components/Paginate/index.tsx
@@ -16,6 +16,7 @@ export interface IProp {
numberMarginPagesDisplayed?: number;
totalEntries?: number;
+ entriesPerPage?: number;
previousLabel?: string;
nextLabel?: string;
@@ -36,6 +37,7 @@ const Pagination: React.FC = ({
numberPageDisplayed = 2,
numberMarginPagesDisplayed = 2,
totalEntries,
+ entriesPerPage = 10,
previousLabel = "Previous",
nextLabel = "Next",
breakLabel = "...",
@@ -181,6 +183,15 @@ const Pagination: React.FC = ({
onHandlePageSelected(page, null);
};
+ const getShowingText = () => {
+ if (!totalEntries) return "";
+
+ const start = (currentPage - 1) * entriesPerPage + 1;
+ const end = Math.min(currentPage * entriesPerPage, totalEntries);
+
+ return `Showing ${start} to ${end} of ${totalEntries}`;
+ };
+
return (
<>
@@ -230,7 +241,7 @@ const Pagination: React.FC = ({
{totalEntries && (
- {`Showing ${currentPage === 1 ? "" : currentPage - 1}0 of ${totalEntries}`}
+ {getShowingText()}
)}