diff --git a/src/components/Navbar/NavbarUntranslated.tsx b/src/components/Navbar/NavbarUntranslated.tsx
index 02e7d37..315490b 100644
--- a/src/components/Navbar/NavbarUntranslated.tsx
+++ b/src/components/Navbar/NavbarUntranslated.tsx
@@ -13,10 +13,7 @@ export default function NavbarUntranslated() {
MyLinks
- Privacy
-
-
- Terms of use
+ GitHub
{status === 'authenticated' ? (
diff --git a/src/constants/paths.ts b/src/constants/paths.ts
index 0ff70bf..cf8c330 100644
--- a/src/constants/paths.ts
+++ b/src/constants/paths.ts
@@ -2,6 +2,7 @@ const PATHS = {
LOGIN: '/login',
LOGOUT: '/logout',
HOME: '/',
+ APP: '/app',
PRIVACY: '/privacy',
TERMS: '/terms',
ADMIN: '/admin',
diff --git a/src/lib/search.tsx b/src/lib/search.tsx
index 4ba14ee..d81938f 100644
--- a/src/lib/search.tsx
+++ b/src/lib/search.tsx
@@ -16,7 +16,7 @@ export function buildSearchItem(
url:
type === 'link'
? (item as LinkWithCategory).url
- : `${PATHS.HOME}?categoryId=${item.id}`,
+ : `${PATHS.APP}?categoryId=${item.id}`,
type,
category: type === 'link' ? (item as LinkWithCategory).category : undefined,
};
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 77dcff7..76b7391 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -23,8 +23,8 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }) {
// TODO: use dynamic locale import
dayjs.locale(i18n.language);
- useHotkeys(Keys.CLOSE_SEARCH_KEY, () => router.push(PATHS.HOME), {
- enabled: router.pathname !== PATHS.HOME,
+ useHotkeys(Keys.CLOSE_SEARCH_KEY, () => router.push(PATHS.APP), {
+ enabled: router.pathname !== PATHS.APP,
enableOnFormTags: ['INPUT'],
});
diff --git a/src/pages/about.tsx b/src/pages/about.tsx
deleted file mode 100644
index ce3e887..0000000
--- a/src/pages/about.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import clsx from 'clsx';
-import Footer from 'components/Footer/Footer';
-import Navbar from 'components/Navbar/Navbar';
-import PageTransition from 'components/PageTransition';
-import { getServerSideTranslation } from 'i18n';
-import { useTranslation } from 'next-i18next';
-import Image from 'next/image';
-import Link from 'next/link';
-import { IconType } from 'react-icons';
-import { AiFillFolderOpen } from 'react-icons/ai';
-import { FaUser } from 'react-icons/fa';
-import { IoIosLink, IoIosSearch } from 'react-icons/io';
-import { IoExtensionPuzzleOutline } from 'react-icons/io5';
-import websiteScreenshot from '../../public/website-screenshot.png';
-
-import Quotes from 'components/Quotes/Quotes';
-import styles from 'styles/about.module.scss';
-
-export default function AboutPage() {
- const { t } = useTranslation('about');
- return (
-
-
-
-
-
-
{t('about:look-title')}
-
-
-
-
-
-
- );
-}
-
-const AboutItem = ({
- title,
- text,
- icon: Icon,
-}: {
- title: string;
- text: string;
- icon: IconType;
-}) => (
-
-
- {title}
- {text}
-
-);
-
-function HeroHeader() {
- const { t } = useTranslation('about');
- return (
-
- {t('about:hero.title')}
- {t('common:slogan')}
-
- {t('about:hero.cta')}
-
-
- );
-}
-
-export const getServerSideProps = async ({ locale }) => ({
- props: {
- ...(await getServerSideTranslation(locale, ['about'])),
- },
-});
diff --git a/src/pages/app.tsx b/src/pages/app.tsx
new file mode 100644
index 0000000..1dbefbf
--- /dev/null
+++ b/src/pages/app.tsx
@@ -0,0 +1,205 @@
+import clsx from 'clsx';
+import Links from 'components/Links/Links';
+import PageTransition from 'components/PageTransition';
+import SideMenu from 'components/SideMenu/SideMenu';
+import SideNavigation from 'components/SideNavigation/SideNavigation';
+import * as Keys from 'constants/keys';
+import PATHS from 'constants/paths';
+import ActiveCategoryContext from 'contexts/activeCategoryContext';
+import CategoriesContext from 'contexts/categoriesContext';
+import FavoritesContext from 'contexts/favoritesContext';
+import GlobalHotkeysContext from 'contexts/globalHotkeysContext';
+import { AnimatePresence } from 'framer-motion';
+import { useMediaQuery } from 'hooks/useMediaQuery';
+import useModal from 'hooks/useModal';
+import { getServerSideTranslation } from 'i18n';
+import getUserCategories from 'lib/category/getUserCategories';
+import sortCategoriesByNextId from 'lib/category/sortCategoriesByNextId';
+import { useRouter } from 'next/router';
+import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react';
+import { useHotkeys } from 'react-hotkeys-hook';
+import { useSwipeable } from 'react-swipeable';
+import styles from 'styles/home.module.scss';
+import { CategoryWithLinks, LinkWithCategory } from 'types/types';
+import { withAuthentication } from 'utils/session';
+
+interface HomePageProps {
+ categories: CategoryWithLinks[];
+ activeCategory: CategoryWithLinks | undefined;
+}
+
+export default function HomePage(props: Readonly) {
+ const isMobile = useMediaQuery('(max-width: 768px)');
+ const { isShowing, open, close } = useModal();
+ const handlers = useSwipeable({
+ trackMouse: true,
+ onSwipedRight: open,
+ });
+
+ useEffect(() => {
+ if (!isMobile && isShowing) {
+ close();
+ }
+ }, [close, isMobile, isShowing]);
+
+ return (
+
+
+
+ {!isMobile && (
+
+
+
+ )}
+
+ {isShowing && (
+
+
+
+ )}
+
+
+
+
+
+ );
+}
+
+function HomeProviders(
+ props: Readonly<{
+ children: ReactNode;
+ categories: CategoryWithLinks[];
+ activeCategory: CategoryWithLinks;
+ }>,
+) {
+ const router = useRouter();
+ const [globalHotkeysEnabled, setGlobalHotkeysEnabled] =
+ useState(true);
+ const [categories, setCategories] = useState(
+ props.categories,
+ );
+ const [activeCategory, setActiveCategory] =
+ useState(props.activeCategory || categories?.[0]);
+
+ const handleChangeCategory = useCallback(
+ (category: CategoryWithLinks) => {
+ setActiveCategory(category);
+ router.push(`${PATHS.APP}?categoryId=${category.id}`);
+ },
+ [router],
+ );
+
+ const favorites = useMemo(
+ () =>
+ categories.reduce((acc, category) => {
+ category.links.forEach((link) =>
+ link.favorite ? acc.push(link) : null,
+ );
+ return acc;
+ }, [] as LinkWithCategory[]),
+ [categories],
+ );
+
+ const categoriesContextValue = useMemo(
+ () => ({ categories, setCategories }),
+ [categories],
+ );
+ const activeCategoryContextValue = useMemo(
+ () => ({ activeCategory, setActiveCategory: handleChangeCategory }),
+ [activeCategory, handleChangeCategory],
+ );
+ const favoritesContextValue = useMemo(() => ({ favorites }), [favorites]);
+ const globalHotkeysContextValue = useMemo(
+ () => ({
+ globalHotkeysEnabled: globalHotkeysEnabled,
+ setGlobalHotkeysEnabled,
+ }),
+ [globalHotkeysEnabled],
+ );
+
+ useHotkeys(
+ Keys.OPEN_CREATE_LINK_KEY,
+ () => {
+ router.push(`${PATHS.LINK.CREATE}?categoryId=${activeCategory.id}`);
+ },
+ { enabled: globalHotkeysEnabled },
+ );
+ useHotkeys(
+ Keys.OPEN_CREATE_CATEGORY_KEY,
+ () => {
+ router.push(PATHS.CATEGORY.CREATE);
+ },
+ { enabled: globalHotkeysEnabled },
+ );
+ return (
+
+
+
+
+ {props.children}
+
+
+
+
+ );
+}
+
+export const getServerSideProps = withAuthentication(
+ async ({ query, session, user, locale }) => {
+ const queryCategoryId = (query?.categoryId as string) || '';
+ const searchQueryParam = (query?.q as string)?.toLowerCase() || '';
+
+ const categories = await getUserCategories(user);
+ if (categories.length === 0) {
+ return {
+ redirect: {
+ destination: PATHS.CATEGORY.CREATE,
+ },
+ };
+ }
+
+ const link = categories
+ .map((category) => category.links)
+ .flat()
+ .find(
+ (link: LinkWithCategory) =>
+ link.name.toLowerCase() === searchQueryParam ||
+ link.url.toLowerCase() === searchQueryParam,
+ );
+ if (link) {
+ return {
+ redirect: {
+ destination: link.url,
+ },
+ };
+ }
+
+ const activeCategory = categories.find(
+ ({ id }) => id === Number(queryCategoryId),
+ );
+ return {
+ props: {
+ session,
+ categories: JSON.parse(
+ JSON.stringify(sortCategoriesByNextId(categories)),
+ ),
+ activeCategory: activeCategory
+ ? JSON.parse(JSON.stringify(activeCategory))
+ : null,
+ ...(await getServerSideTranslation(locale, ['home'])),
+ },
+ };
+ },
+);
diff --git a/src/pages/category/create.tsx b/src/pages/category/create.tsx
index 4e47b93..c1d2b07 100644
--- a/src/pages/category/create.tsx
+++ b/src/pages/category/create.tsx
@@ -44,7 +44,7 @@ export default function PageCreateCategory({
body: { name, description, nextId: null },
})
.then((data) =>
- router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
+ router.push(`${PATHS.APP}?categoryId=${data?.categoryId}`),
)
.catch(setError)
.finally(() => setSubmitted(false));
diff --git a/src/pages/category/edit/[cid].tsx b/src/pages/category/edit/[cid].tsx
index 4f91e71..b19ce80 100644
--- a/src/pages/category/edit/[cid].tsx
+++ b/src/pages/category/edit/[cid].tsx
@@ -46,7 +46,7 @@ export default function PageEditCategory({
body: { name, description, nextId: category.nextId },
})
.then((data) =>
- router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
+ router.push(`${PATHS.APP}?categoryId=${data?.categoryId}`),
)
.catch(setError)
.finally(() => setSubmitted(false));
@@ -91,7 +91,7 @@ export const getServerSideProps = withAuthentication(
if (!category) {
return {
redirect: {
- destination: PATHS.HOME,
+ destination: PATHS.APP,
},
};
}
diff --git a/src/pages/category/remove/[cid].tsx b/src/pages/category/remove/[cid].tsx
index 7f09ac2..0a2785d 100644
--- a/src/pages/category/remove/[cid].tsx
+++ b/src/pages/category/remove/[cid].tsx
@@ -39,7 +39,7 @@ export default function PageRemoveCategory({
url: `${PATHS.API.CATEGORY}/${category.id}`,
method: 'DELETE',
})
- .then(() => router.push(PATHS.HOME))
+ .then(() => router.push(PATHS.APP))
.catch(setError)
.finally(() => setSubmitted(false));
};
@@ -100,7 +100,7 @@ export const getServerSideProps = withAuthentication(
if (!category) {
return {
redirect: {
- destination: PATHS.HOME,
+ destination: PATHS.APP,
},
};
}
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 8912d80..c26be6f 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,205 +1,105 @@
import clsx from 'clsx';
-import Links from 'components/Links/Links';
+import Footer from 'components/Footer/Footer';
+import Navbar from 'components/Navbar/Navbar';
import PageTransition from 'components/PageTransition';
-import SideMenu from 'components/SideMenu/SideMenu';
-import SideNavigation from 'components/SideNavigation/SideNavigation';
-import * as Keys from 'constants/keys';
-import PATHS from 'constants/paths';
-import ActiveCategoryContext from 'contexts/activeCategoryContext';
-import CategoriesContext from 'contexts/categoriesContext';
-import FavoritesContext from 'contexts/favoritesContext';
-import GlobalHotkeysContext from 'contexts/globalHotkeysContext';
-import { AnimatePresence } from 'framer-motion';
-import { useMediaQuery } from 'hooks/useMediaQuery';
-import useModal from 'hooks/useModal';
import { getServerSideTranslation } from 'i18n';
-import getUserCategories from 'lib/category/getUserCategories';
-import sortCategoriesByNextId from 'lib/category/sortCategoriesByNextId';
-import { useRouter } from 'next/router';
-import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react';
-import { useHotkeys } from 'react-hotkeys-hook';
-import { useSwipeable } from 'react-swipeable';
-import styles from 'styles/home.module.scss';
-import { CategoryWithLinks, LinkWithCategory } from 'types/types';
-import { withAuthentication } from 'utils/session';
+import { useTranslation } from 'next-i18next';
+import Image from 'next/image';
+import Link from 'next/link';
+import { IconType } from 'react-icons';
+import { AiFillFolderOpen } from 'react-icons/ai';
+import { FaUser } from 'react-icons/fa';
+import { IoIosLink, IoIosSearch } from 'react-icons/io';
+import { IoExtensionPuzzleOutline } from 'react-icons/io5';
+import websiteScreenshot from '../../public/website-screenshot.png';
-interface HomePageProps {
- categories: CategoryWithLinks[];
- activeCategory: CategoryWithLinks | undefined;
-}
-
-export default function HomePage(props: Readonly) {
- const isMobile = useMediaQuery('(max-width: 768px)');
- const { isShowing, open, close } = useModal();
- const handlers = useSwipeable({
- trackMouse: true,
- onSwipedRight: open,
- });
-
- useEffect(() => {
- if (!isMobile && isShowing) {
- close();
- }
- }, [close, isMobile, isShowing]);
+import Quotes from 'components/Quotes/Quotes';
+import PATHS from 'constants/paths';
+import styles from 'styles/about.module.scss';
+export default function AboutPage() {
+ const { t } = useTranslation('about');
return (
-
-
-
- {!isMobile && (
-
-
-
- )}
-
- {isShowing && (
-
-
-
- )}
-
-
+
+
+
+
+
{t('about:look-title')}
+
+
-
+
+
);
}
-function HomeProviders(
- props: Readonly<{
- children: ReactNode;
- categories: CategoryWithLinks[];
- activeCategory: CategoryWithLinks;
- }>,
-) {
- const router = useRouter();
- const [globalHotkeysEnabled, setGlobalHotkeysEnabled] =
- useState(true);
- const [categories, setCategories] = useState(
- props.categories,
- );
- const [activeCategory, setActiveCategory] =
- useState(props.activeCategory || categories?.[0]);
+const AboutItem = ({
+ title,
+ text,
+ icon: Icon,
+}: {
+ title: string;
+ text: string;
+ icon: IconType;
+}) => (
+
+
+ {title}
+ {text}
+
+);
- const handleChangeCategory = useCallback(
- (category: CategoryWithLinks) => {
- setActiveCategory(category);
- router.push(`${PATHS.HOME}?categoryId=${category.id}`);
- },
- [router],
- );
-
- const favorites = useMemo(
- () =>
- categories.reduce((acc, category) => {
- category.links.forEach((link) =>
- link.favorite ? acc.push(link) : null,
- );
- return acc;
- }, [] as LinkWithCategory[]),
- [categories],
- );
-
- const categoriesContextValue = useMemo(
- () => ({ categories, setCategories }),
- [categories],
- );
- const activeCategoryContextValue = useMemo(
- () => ({ activeCategory, setActiveCategory: handleChangeCategory }),
- [activeCategory, handleChangeCategory],
- );
- const favoritesContextValue = useMemo(() => ({ favorites }), [favorites]);
- const globalHotkeysContextValue = useMemo(
- () => ({
- globalHotkeysEnabled: globalHotkeysEnabled,
- setGlobalHotkeysEnabled,
- }),
- [globalHotkeysEnabled],
- );
-
- useHotkeys(
- Keys.OPEN_CREATE_LINK_KEY,
- () => {
- router.push(`${PATHS.LINK.CREATE}?categoryId=${activeCategory.id}`);
- },
- { enabled: globalHotkeysEnabled },
- );
- useHotkeys(
- Keys.OPEN_CREATE_CATEGORY_KEY,
- () => {
- router.push(PATHS.CATEGORY.CREATE);
- },
- { enabled: globalHotkeysEnabled },
- );
+function HeroHeader() {
+ const { t } = useTranslation('about');
return (
-
-
-
-
- {props.children}
-
-
-
-
+
+ {t('about:hero.title')}
+ {t('common:slogan')}
+
+ {t('about:hero.cta')}
+
+
);
}
-export const getServerSideProps = withAuthentication(
- async ({ query, session, user, locale }) => {
- const queryCategoryId = (query?.categoryId as string) || '';
- const searchQueryParam = (query?.q as string)?.toLowerCase() || '';
-
- const categories = await getUserCategories(user);
- if (categories.length === 0) {
- return {
- redirect: {
- destination: PATHS.CATEGORY.CREATE,
- },
- };
- }
-
- const link = categories
- .map((category) => category.links)
- .flat()
- .find(
- (link: LinkWithCategory) =>
- link.name.toLowerCase() === searchQueryParam ||
- link.url.toLowerCase() === searchQueryParam,
- );
- if (link) {
- return {
- redirect: {
- destination: link.url,
- },
- };
- }
-
- const activeCategory = categories.find(
- ({ id }) => id === Number(queryCategoryId),
- );
- return {
- props: {
- session,
- categories: JSON.parse(
- JSON.stringify(sortCategoriesByNextId(categories)),
- ),
- activeCategory: activeCategory
- ? JSON.parse(JSON.stringify(activeCategory))
- : null,
- ...(await getServerSideTranslation(locale, ['home'])),
- },
- };
+export const getServerSideProps = async ({ locale }) => ({
+ props: {
+ ...(await getServerSideTranslation(locale, ['about'])),
},
-);
+});
diff --git a/src/pages/link/create.tsx b/src/pages/link/create.tsx
index 4991e1b..1201efd 100644
--- a/src/pages/link/create.tsx
+++ b/src/pages/link/create.tsx
@@ -59,7 +59,7 @@ export default function PageCreateLink({
body: { name, url, description, favorite, categoryId },
})
.then((data) =>
- router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
+ router.push(`${PATHS.APP}?categoryId=${data?.categoryId}`),
)
.catch(setError)
.finally(() => setSubmitted(false));
@@ -129,7 +129,7 @@ export const getServerSideProps = withAuthentication(
if (categories.length === 0) {
return {
redirect: {
- destination: PATHS.HOME,
+ destination: PATHS.APP,
},
};
}
diff --git a/src/pages/link/edit/[lid].tsx b/src/pages/link/edit/[lid].tsx
index a79656d..84a5190 100644
--- a/src/pages/link/edit/[lid].tsx
+++ b/src/pages/link/edit/[lid].tsx
@@ -65,7 +65,7 @@ export default function PageEditLink({
body: { name, url, description, favorite, categoryId },
})
.then((data) =>
- router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
+ router.push(`${PATHS.APP}?categoryId=${data?.categoryId}`),
)
.catch(setError)
.finally(() => setSubmitted(false));
@@ -139,7 +139,7 @@ export const getServerSideProps = withAuthentication(
if (!link) {
return {
redirect: {
- destination: PATHS.HOME,
+ destination: PATHS.APP,
},
};
}
diff --git a/src/pages/link/remove/[lid].tsx b/src/pages/link/remove/[lid].tsx
index 1924774..da95c01 100644
--- a/src/pages/link/remove/[lid].tsx
+++ b/src/pages/link/remove/[lid].tsx
@@ -38,7 +38,7 @@ export default function PageRemoveLink({
method: 'DELETE',
})
.then((data) =>
- router.push(`${PATHS.HOME}?categoryId=${data?.categoryId}`),
+ router.push(`${PATHS.APP}?categoryId=${data?.categoryId}`),
)
.catch(setError)
.finally(() => setSubmitted(false));
@@ -108,7 +108,7 @@ export const getServerSideProps = withAuthentication(
if (!link) {
return {
redirect: {
- destination: PATHS.HOME,
+ destination: PATHS.APP,
},
};
}
diff --git a/src/pages/login.tsx b/src/pages/login.tsx
index 7a2f5e6..979d37f 100644
--- a/src/pages/login.tsx
+++ b/src/pages/login.tsx
@@ -66,7 +66,7 @@ export async function getServerSideProps({ req, res, locale }) {
if (user) {
return {
redirect: {
- destination: PATHS.HOME,
+ destination: PATHS.APP,
},
};
}