Skip to content

Commit

Permalink
Improve Communities page SSR
Browse files Browse the repository at this point in the history
  • Loading branch information
Oksamies committed Feb 29, 2024
1 parent 0308d91 commit 9c4be55
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 103 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.root {
display: flex;
flex-direction: column;
gap: var(--gap--16);
}

.searchTextInput {
width: 100%;
}

@media (min-width: 40rem) {
.searchTextInput {
width: 50%;
}

.root {
flex-direction: row;
justify-content: space-between;
}
}

.searchFilters {
display: flex;
flex: 1 1 auto;
gap: var(--gap--16);
align-content: center;
justify-content: flex-end;
}

.searchFiltersSortLabel {
align-self: center;
color: var(--color-text--tertiary);
font-weight: var(--font-weight-bold);
}
94 changes: 94 additions & 0 deletions apps/cyberstorm-nextjs/app/communities/@searchAndOrder/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"use client";
import styles from "./SearchAndOrder.module.css";
import { TextInput, Select } from "@thunderstore/cyberstorm";
import { useCallback, useEffect, useState } from "react";
import { useDebounce } from "use-debounce";

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faSearch,
faArrowDownAZ,
faStar,
} from "@fortawesome/free-solid-svg-icons";
import { faFire } from "@fortawesome/pro-solid-svg-icons";
import { usePathname, useSearchParams } from "next/navigation";
import { useRouter } from "next/navigation";

enum SortOptions {
Name = "name",
Latest = "-datetime_created",
Popular = "-aggregated_fields__download_count",
}

export default function Page() {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();

const createQueryString = useCallback(
(name: string, value: string, isDefault?: boolean) => {
const params = new URLSearchParams(searchParams.toString());
if (isDefault || value.length === 0) {
params.delete(name);
} else {
params.set(name, value);
}

return params.toString();
},
[searchParams]
);

const [order, setOrder] = useState(SortOptions.Popular);

const changeOrder = (v: SortOptions) => {
setOrder(v);
router.push(
pathname + "?" + createQueryString("order", v, v === SortOptions.Popular)
);
};

const [searchValue, setSearchValue] = useState("");
const [debouncedSearchValue] = useDebounce(searchValue, 300);

useEffect(() => {
router.push(
pathname + "?" + createQueryString("search", debouncedSearchValue)
);
}, [createQueryString, debouncedSearchValue, pathname, router]);

return (
<div className={styles.root}>
<div className={styles.searchTextInput}>
<TextInput
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
placeholder="Search communities..."
leftIcon={<FontAwesomeIcon icon={faSearch} />}
/>
</div>
<div className={styles.searchFilters}>
<div className={styles.searchFiltersSortLabel}>Sort by</div>
<Select onChange={changeOrder} options={selectOptions} value={order} />
</div>
</div>
);
}

const selectOptions = [
{
value: SortOptions.Name,
label: "Name",
leftIcon: <FontAwesomeIcon icon={faArrowDownAZ} />,
},
{
value: SortOptions.Latest,
label: "Latest",
leftIcon: <FontAwesomeIcon icon={faStar} />,
},
{
value: SortOptions.Popular,
label: "Popular",
leftIcon: <FontAwesomeIcon icon={faFire} />,
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import styles from "./SearchAndOrder.module.css";

export const SearchAndOrderSkeleton = () => {
return <div className={styles.root}>TODO: SKELETON</div>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@
flex-direction: column;
}

.topNavigation {
display: flex;
flex-direction: column;
gap: var(--gap--16);
}

.filters {
display: flex;
flex-direction: column;
Expand Down
105 changes: 8 additions & 97 deletions apps/cyberstorm-nextjs/app/communities/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,73 +1,17 @@
"use client";
import rootStyles from "../RootLayout.module.css";
import styles from "./CommunitiesLayout.module.css";
import {
TextInput,
Select,
BreadCrumbs,
PageHeader,
} from "@thunderstore/cyberstorm";
import { ReactNode, Suspense, useCallback, useEffect, useState } from "react";
import { useDebounce } from "use-debounce";
import { BreadCrumbs, PageHeader } from "@thunderstore/cyberstorm";
import { ReactNode, Suspense } from "react";

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faArrowDownAZ,
faSearch,
faStar,
} from "@fortawesome/free-solid-svg-icons";
import { faFire } from "@fortawesome/pro-solid-svg-icons";
import { CommunityListSkeleton } from "./@communityList/CommunityListSkeleton";
import { usePathname, useSearchParams } from "next/navigation";
import { useRouter } from "next/navigation";

enum SortOptions {
Name = "name",
Latest = "-datetime_created",
Popular = "-aggregated_fields__download_count",
}
import { SearchAndOrderSkeleton } from "./@searchAndOrder/searchAndOrderSkeleton";

export default function CommunitiesLayout({
communityList,
searchAndOrder,
}: {
communityList: ReactNode;
searchAndOrder: ReactNode;
}) {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();

const createQueryString = useCallback(
(name: string, value: string, isDefault?: boolean) => {
const params = new URLSearchParams(searchParams.toString());
if (isDefault || value.length === 0) {
params.delete(name);
} else {
params.set(name, value);
}

return params.toString();
},
[searchParams]
);

const [order, setOrder] = useState(SortOptions.Popular);

const changeOrder = (v: SortOptions) => {
setOrder(v);
router.push(
pathname + "?" + createQueryString("order", v, v === SortOptions.Popular)
);
};

const [searchValue, setSearchValue] = useState("");
const [debouncedSearchValue] = useDebounce(searchValue, 300);

useEffect(() => {
router.push(
pathname + "?" + createQueryString("search", debouncedSearchValue)
);
}, [createQueryString, debouncedSearchValue, pathname, router]);

return (
<section className={rootStyles.content}>
<div className={rootStyles.container}>
Expand All @@ -77,24 +21,9 @@ export default function CommunitiesLayout({
<PageHeader title="Communities" />
</header>
<main className={rootStyles.main}>
<div className={styles.filters}>
<div className={styles.searchTextInput}>
<TextInput
onChange={(e) => setSearchValue(e.target.value)}
value={searchValue}
placeholder="Search communities..."
leftIcon={<FontAwesomeIcon icon={faSearch} />}
/>
</div>
<div className={styles.searchFilters}>
<div className={styles.searchFiltersSortLabel}>Sort by</div>
<Select
onChange={changeOrder}
options={selectOptions}
value={order}
/>
</div>
</div>
<Suspense fallback={<SearchAndOrderSkeleton />}>
{searchAndOrder}
</Suspense>
<Suspense fallback={<CommunityListSkeleton />}>
{communityList}
</Suspense>
Expand All @@ -104,21 +33,3 @@ export default function CommunitiesLayout({
</section>
);
}

const selectOptions = [
{
value: SortOptions.Name,
label: "Name",
leftIcon: <FontAwesomeIcon icon={faArrowDownAZ} />,
},
{
value: SortOptions.Latest,
label: "Latest",
leftIcon: <FontAwesomeIcon icon={faStar} />,
},
{
value: SortOptions.Popular,
label: "Popular",
leftIcon: <FontAwesomeIcon icon={faFire} />,
},
];

0 comments on commit 9c4be55

Please sign in to comment.