Skip to content

Commit

Permalink
feat(forum): Add local storage for category accordion
Browse files Browse the repository at this point in the history
  • Loading branch information
aXenDeveloper committed Feb 23, 2024
1 parent b833df3 commit d421597
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 57 deletions.
2 changes: 1 addition & 1 deletion frontend/components/editor/plugins/emoji.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { CONFIG } from "@/config";
const convertEmoji = (emoji: Emoji[]) => {
const localStorageSkinToneIndex =
typeof window !== "undefined"
? localStorage.getItem(CONFIG.editor.skin_tone)
? localStorage.getItem(CONFIG.local_storage.editor_skin_tone)
: null;
const result: Map<string, string> = new Map();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface Props {

export const ContentEmojiButtonEditor = ({ setOpen }: Props) => {
const localStorageSkinToneIndex = localStorage.getItem(
CONFIG.editor.skin_tone
CONFIG.local_storage.editor_skin_tone
);
const [searchValue, setSearchValue] = useState("");
const [searchResults, setSearchResults] = useState<string[] | null>(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ export const SkinSelectEmojiButtonEditor = ({
key={item}
className="flex gap-2"
onClick={() => {
localStorage.setItem(CONFIG.editor.skin_tone, index.toString());
localStorage.setItem(
CONFIG.local_storage.editor_skin_tone,
index.toString()
);
setSkinToneIndex(index);
}}
>
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/icon/input/content/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const ContentIconInput = (props: IconInputProps) => {
const [search, setSearch] = useState("");
const [activeTab, setActiveTab] = useState<Tab>(Tab.Icon);
const localStorageSkinToneIndex = localStorage.getItem(
CONFIG.editor.skin_tone
CONFIG.local_storage.editor_skin_tone
);
const [skinToneIndex, setSkinToneIndex] = useState(
localStorageSkinToneIndex ? +localStorageSkinToneIndex : 0
Expand Down
8 changes: 4 additions & 4 deletions frontend/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ const ENVS = {

export const CONFIG = {
graphql_url: ENVS.graphql_url ?? "http://localhost:8080",
editor: {
skin_tone: "emoji:skin-tone"
},
backend_url: ENVS.backend_url ?? "http://localhost:8080"
backend_url: ENVS.backend_url ?? "http://localhost:8080",
local_storage: {
editor_skin_tone: "emoji:skin-tone"
}
};
19 changes: 19 additions & 0 deletions frontend/hooks/forums/forum/use-wrapper-category-forum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {
createContext,
useContext,
type Dispatch,
type SetStateAction
} from "react";

interface Args {
open: boolean;
setOpen: Dispatch<SetStateAction<boolean>>;
}

export const WrapperCategoryForumContext = createContext<Args>({
open: true,
setOpen: () => {}
});

export const useWrapperCategoryForum = () =>
useContext(WrapperCategoryForumContext);
10 changes: 6 additions & 4 deletions frontend/themes/1/forum/views/forum/forums/category/category.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { ItemForum, type ItemForumProps } from "../item/item-forum";
import type { TextLanguage } from "@/graphql/hooks";
import { useTextLang } from "@/hooks/core/use-text-lang";
import { ReadOnlyEditor } from "@/components/editor/read-only/read-only-editor";
import { AccordionContent } from "@/components/ui/accordion";
import { WrapperCategoryForum } from "./wrapper";
import { ChevronCategoryForumButton } from "./chevron-button";
import { ChildrenWrapperCategoryForum } from "./children-wrapper";

interface Props {
description: TextLanguage[];
Expand Down Expand Up @@ -45,15 +45,17 @@ export const CategoryForum = ({ children, description, id, name }: Props) => {
)}
</div>

{children && children.length > 0 && <ChevronCategoryForumButton />}
{children && children.length > 0 && (
<ChevronCategoryForumButton id={id} />
)}
</div>

{children && children.length > 0 && (
<AccordionContent className="[&>div]:p-0">
<ChildrenWrapperCategoryForum>
{children.map(child => (
<ItemForum key={child.id} {...child} />
))}
</AccordionContent>
</ChildrenWrapperCategoryForum>
)}
</CardContent>
</Card>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
"use client";

import { ChevronDown } from "lucide-react";
import * as Accordion from "@radix-ui/react-accordion";

import { Button } from "@/components/ui/button";
import { useWrapperCategoryForum } from "@/hooks/forums/forum/use-wrapper-category-forum";
import { LOCAL_STORAGE_KEY } from "./wrapper";

interface Props {
id: number;
}

export const ChevronCategoryForumButton = ({ id }: Props) => {
const { open, setOpen } = useWrapperCategoryForum();

export const ChevronCategoryForumButton = () => {
return (
<Accordion.Header>
<Accordion.Trigger asChild>
<Button
className="text-muted-foreground hover:text-foreground flex-shrink-0 [&[data-state=open]>svg]:rotate-180 [&>svg]:transition-transform"
variant="ghost"
size="icon"
tooltip=""
>
<ChevronDown />
</Button>
</Accordion.Trigger>
</Accordion.Header>
<Button
className="text-muted-foreground hover:text-foreground flex-shrink-0 [&[data-state=open]>svg]:rotate-180 [&>svg]:transition-transform"
variant="ghost"
size="icon"
data-state={open ? "open" : "closed"}
tooltip=""
onClick={() => {
setOpen(prev => !prev);
const currentId = id.toString();

const prevIds =
localStorage.getItem(LOCAL_STORAGE_KEY)?.split(",") || [];
const valueToSet = prevIds.includes(currentId)
? prevIds.filter(i => i !== currentId)
: [...prevIds, currentId];

localStorage.setItem(LOCAL_STORAGE_KEY, valueToSet.join(","));
}}
>
<ChevronDown />
</Button>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use client";

import { AnimatePresence, motion } from "framer-motion";
import type { ReactNode } from "react";

import { useWrapperCategoryForum } from "@/hooks/forums/forum/use-wrapper-category-forum";

interface Props {
children: ReactNode;
}

export const ChildrenWrapperCategoryForum = ({ children }: Props) => {
const { open } = useWrapperCategoryForum();

return (
<AnimatePresence initial={false}>
{open && (
<motion.div
initial="collapsed"
animate="open"
exit="collapsed"
className="overflow-hidden"
variants={{
open: { opacity: 1, height: "auto" },
collapsed: { opacity: 0, height: 0 }
}}
>
{children}
</motion.div>
)}
</AnimatePresence>
);
};
23 changes: 20 additions & 3 deletions frontend/themes/1/forum/views/forum/forums/category/wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
"use client";

import * as Accordion from "@radix-ui/react-accordion";
import type { ReactNode } from "react";
import { useState, type ReactNode, useEffect } from "react";

import { WrapperCategoryForumContext } from "@/hooks/forums/forum/use-wrapper-category-forum";

interface Props {
children: ReactNode;
id: number;
}

export const LOCAL_STORAGE_KEY = "forum:category-accordion";

export const WrapperCategoryForum = ({ children, id }: Props) => {
return <Accordion.Item value={`${id}`}>{children}</Accordion.Item>;
const [open, setOpen] = useState(true);

useEffect(() => {
const ids = localStorage.getItem(LOCAL_STORAGE_KEY)?.split(",");

if (ids?.includes(id.toString())) {
setOpen(false);
}
}, []);

return (
<WrapperCategoryForumContext.Provider value={{ open, setOpen }}>
{children}
</WrapperCategoryForumContext.Provider>
);
};
13 changes: 5 additions & 8 deletions frontend/themes/1/forum/views/forum/forums/forums-forum-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useTranslations } from "next-intl";
import type { Forum_Forums__ShowQuery } from "@/graphql/hooks";
import { CategoryForum } from "./category/category";
import { HeaderContent } from "@/components/header-content/header-content";
import { WrapperForumsForum } from "./wrapper";

export interface ForumsForumViewProps {
data: Forum_Forums__ShowQuery;
Expand All @@ -22,13 +21,11 @@ export default function ForumsForumView({
<HeaderContent h1={t("forum")} />

{edges.length ? (
<WrapperForumsForum forums={edges}>
<div className="flex flex-col gap-4">
{edges.map(edge => (
<CategoryForum key={edge.id} {...edge} />
))}
</div>
</WrapperForumsForum>
<div className="flex flex-col gap-4">
{edges.map(edge => (
<CategoryForum key={edge.id} {...edge} />
))}
</div>
) : (
<div className="text-center">{tCore("no_results")}</div>
)}
Expand Down
20 changes: 0 additions & 20 deletions frontend/themes/1/forum/views/forum/forums/wrapper.tsx

This file was deleted.

0 comments on commit d421597

Please sign in to comment.