atomsystem 0.1.25 → 0.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,306 @@
1
+ "use client";
2
+ import Link from "next/link";
3
+ import Image from "next/image";
4
+ import { useEffect, useState } from "react";
5
+ import { usePathname } from "next/navigation";
6
+ import clsx from "clsx";
7
+ import { useMediaQuery } from "react-responsive";
8
+
9
+ interface NavItemsAttr {
10
+ type?: "topnav" | "sidenav";
11
+ navMenu: {
12
+ name: string;
13
+ path?: string;
14
+ }[];
15
+ }
16
+
17
+ // Custom CSS classes are now used via css/navigation.css
18
+
19
+ const handleNavToggle = (targetId: string) => {
20
+ const el = document.getElementById(targetId);
21
+ if (el) {
22
+ const isHidden = el.style.display === "none" || el.style.display === "";
23
+ el.style.display = isHidden ? "block" : "none";
24
+ }
25
+ };
26
+
27
+ const Navigation = ({
28
+ children,
29
+ id,
30
+ className,
31
+ type = "topnav",
32
+ }: {
33
+ children: React.ReactNode;
34
+ id?: string;
35
+ className?: string;
36
+ type?: "topnav" | "sidenav";
37
+ }) => {
38
+ const isMobile = useMediaQuery({ maxWidth: 767 });
39
+
40
+ const mobileClose = (e: React.MouseEvent) => {
41
+ if (isMobile) {
42
+ if (id) {
43
+ handleNavToggle(id);
44
+ }
45
+ }
46
+ };
47
+
48
+ return (
49
+ <nav
50
+ id={id ? id : undefined}
51
+ className={`nav-container nav-${type} ${className} overflow-auto`}
52
+ onClick={mobileClose}
53
+ >
54
+ {children}
55
+ </nav>
56
+ );
57
+ };
58
+
59
+ const NavItems = ({ navMenu, type = "sidenav" }: NavItemsAttr) => {
60
+ const pathname = usePathname();
61
+
62
+ return (
63
+ <ul className={clsx(`nav-${type}`, { "flex flex-row items-center nav-gap": type === "topnav" })}>
64
+ {navMenu.map((menu) => {
65
+ return (
66
+ <li className="relative group" key={menu.name}>
67
+ <div className={clsx("flex justify-between items-center pr-4")}>
68
+ <Link
69
+ href={menu.path || "#"}
70
+ className={`${pathname === menu.path ? "nav-text-active" : "nav-text-standard"} nav-${type} block hover:opacity-80 transition-opacity nav-padding`}
71
+ >
72
+ {menu.name}
73
+ </Link>
74
+ </div>
75
+ </li>
76
+ );
77
+ })}
78
+ </ul>
79
+ );
80
+ };
81
+
82
+ const NavToggleButton = ({
83
+ children,
84
+ targetId,
85
+ className,
86
+ }: {
87
+ children: React.ReactNode;
88
+ targetId: string;
89
+ className?: string;
90
+ }) => {
91
+ return (
92
+ <button className={className} onClick={() => handleNavToggle(targetId)}>
93
+ {children}
94
+ </button>
95
+ );
96
+ };
97
+
98
+ const Sidebar = ({ navMenu, type = "sidenav" }: NavItemsAttr) => {
99
+ return (
100
+ <nav
101
+ className={clsx(
102
+ `relative nav-container nav-${type} w-full md:w-[320px] h-full z-20 left-0 overflow-auto`
103
+ )}
104
+ >
105
+ <ul>
106
+ {navMenu.map((menu, idx) => {
107
+ return (
108
+ <li className="relative group" key={menu.name + idx}>
109
+ <div className={clsx("flex justify-between items-center pr-4")}>
110
+ <Link
111
+ href={menu.path || "#"}
112
+ className={clsx(
113
+ `block nav-text-standard nav-${type} hover:opacity-80 transition-opacity nav-padding`
114
+ )}
115
+ >
116
+ {menu.name}
117
+ </Link>
118
+ </div>
119
+ </li>
120
+ );
121
+ })}
122
+ </ul>
123
+ </nav>
124
+ );
125
+ };
126
+
127
+ const GlobalNav = ({
128
+ type = "sidebar",
129
+ navMenu,
130
+ brand = true,
131
+ }: {
132
+ type?: "sidebar" | "topmenu" | "mobile";
133
+ navMenu: {
134
+ name: string;
135
+ path?: string;
136
+ subItems?: { name: string; path: string }[];
137
+ label?: boolean;
138
+ }[];
139
+ brand?: boolean;
140
+ }) => {
141
+ const [windowSize, setWindowSize] = useState<number>(); // 초기값 설정
142
+ const [toggleMenu, setToggleMenu] = useState<boolean>(true);
143
+ const pathname = usePathname();
144
+ const [openSubMenu, setOpenSubMenu] = useState<Record<string, boolean>>({});
145
+
146
+ // 윈도우 사이즈 추적
147
+ useEffect(() => {
148
+ const handleResize = () => {
149
+ setWindowSize(window.innerWidth); // 윈도우 사이즈 업데이트
150
+ };
151
+
152
+ window.addEventListener("resize", handleResize); // 리사이즈 이벤트 리스너 추가
153
+
154
+ return () => window.removeEventListener("resize", handleResize); // 컴포넌트 언마운트 시 리스너 제거
155
+ }, [windowSize]);
156
+
157
+ // 초기 토글 값 설정
158
+ useEffect(() => {
159
+ if (window.innerWidth > 768) {
160
+ } else {
161
+ setToggleMenu(false);
162
+ }
163
+ }, []);
164
+
165
+ const toggleSubMenu = (menuName: string) => {
166
+ setOpenSubMenu((prev) => ({
167
+ ...prev,
168
+ [menuName]: !prev[menuName],
169
+ }));
170
+ };
171
+
172
+ const navType = type === "sidebar" ? "sidenav" : "topnav";
173
+
174
+ return (
175
+ <nav
176
+ className={clsx(
177
+ `fixed top-0 md:relative w-full nav-container nav-${navType} z-20 left-0 ${toggleMenu ? "block" : "hidden"}`,
178
+ { [`h-full max-w-80 overflow-auto border-r nav-border`]: type == "sidebar" },
179
+ { [`h-auto flex flex-row items-center border-b nav-border nav-${navType}`]: type == "topmenu" }
180
+ )}
181
+ >
182
+ {/* brand */}
183
+ {brand ? (
184
+ <div className="brand">
185
+ <div className={`flex items-center justify-between`}>
186
+ <Link href={"/"}>
187
+ <Image
188
+ src={"/images/global/logo.png"}
189
+ alt="Logo"
190
+ width={180}
191
+ height={45}
192
+ draggable="false"
193
+ ></Image>
194
+ </Link>
195
+ <button
196
+ className={`fixed shadow-md rounded-full nav-bg nav-${navType} border nav-border w-12 h-12 top-6 left-6 cursor-pointer z-50`}
197
+ onClick={() => setToggleMenu(!toggleMenu)}
198
+ >
199
+ <span
200
+ className={`material-symbols-outlined nav-text-standard nav-${navType}`}
201
+ style={{ fontSize: "16px" }}
202
+ >
203
+ menu
204
+ </span>
205
+ </button>
206
+ </div>
207
+ </div>
208
+ ) : null}
209
+ {/* List */}
210
+ <ul
211
+ className={clsx("", {
212
+ "flex flex-row": type == "topmenu",
213
+ })}
214
+ >
215
+ {navMenu.map((menu, idx) => {
216
+ switch (true) {
217
+ case menu.label === true && type == "sidebar":
218
+ return (
219
+ <p
220
+ key={menu.name + idx}
221
+ className={`nav-text-sub nav-${navType} mt-2 mb-0 nav-padding`}
222
+ >
223
+ {menu.name}
224
+ </p>
225
+ );
226
+ default:
227
+ return (
228
+ <li className="relative group" key={menu.name}>
229
+ <div
230
+ className={clsx("flex justify-between items-center pr-4")}
231
+ >
232
+ <Link
233
+ href={menu.path || "#"}
234
+ className={clsx(
235
+ `block nav-text-standard nav-${navType} nav-padding`,
236
+ {
237
+ "nav-text-active":
238
+ (menu.path && menu.path == pathname) ||
239
+ menu.subItems?.some((sub) => sub.path === pathname),
240
+ }
241
+ )}
242
+ >
243
+ {menu.name}
244
+ </Link>
245
+ {menu.subItems && type == "sidebar" ? (
246
+ <button
247
+ className="cursor-pointer"
248
+ onClick={() => toggleSubMenu(menu.name)}
249
+ >
250
+ <span
251
+ className={clsx(
252
+ `material-symbols-outlined nav-text-sub nav-${navType} transition-transform`,
253
+ {
254
+ "rotate-90": openSubMenu[menu.name],
255
+ }
256
+ )}
257
+ style={{ fontSize: "16px" }}
258
+ >
259
+ keyboard_arrow_right
260
+ </span>
261
+ </button>
262
+ ) : null}
263
+ </div>
264
+ {menu.subItems ? (
265
+ <ul
266
+ className={clsx(
267
+ "block",
268
+ {
269
+ [`hidden absolute top-[42px] group-hover:block hover:block nav-bg nav-${navType} border nav-border`]:
270
+ type == "topmenu",
271
+ },
272
+ {
273
+ hidden: !openSubMenu[menu.name] && type == "sidebar",
274
+ }
275
+ )}
276
+ >
277
+ {menu.subItems.map((submenu) => {
278
+ return (
279
+ <li key={submenu.name}>
280
+ <Link
281
+ className={clsx(
282
+ `block nav-text-standard nav-${navType} nav-padding`,
283
+ {
284
+ "nav-text-active": submenu.path == pathname,
285
+ },
286
+ { "pl-12 ": type == "sidebar" }
287
+ )}
288
+ href={submenu.path}
289
+ >
290
+ {submenu.name}
291
+ </Link>
292
+ </li>
293
+ );
294
+ })}
295
+ </ul>
296
+ ) : null}
297
+ </li>
298
+ );
299
+ }
300
+ })}
301
+ </ul>
302
+ </nav>
303
+ );
304
+ };
305
+ export default Navigation;
306
+ export { Sidebar, GlobalNav, NavToggleButton, NavItems };
@@ -34,7 +34,7 @@ const Pagination = ({
34
34
  };
35
35
 
36
36
  return (
37
- <div className="text-[#999] flex">
37
+ <div className="pagination">
38
38
  <button
39
39
  disabled={pageStart === 1}
40
40
  onClick={() => {
@@ -43,11 +43,11 @@ const Pagination = ({
43
43
  setPageStart(newStart);
44
44
  onPageChange(newStart);
45
45
  }}
46
- className="px-2 py-8 cursor-pointer disabled:opacity-40"
46
+ className="pagination-btn"
47
47
  >
48
48
  <span className="material-symbols-outlined">keyboard_arrow_left</span>
49
49
  </button>
50
- <ul className="flex w-full">
50
+ <ul className="pagination-list">
51
51
  {[...Array(pageRange)].map((_, i) => {
52
52
  const page = pageStart + i;
53
53
 
@@ -74,8 +74,8 @@ const Pagination = ({
74
74
  }
75
75
  scrollTop();
76
76
  }}
77
- className={` w-full text-center py-8 cursor-pointer px-2 ${
78
- currentPage === page ? "text-primary" : ""
77
+ className={`pagination-item ${
78
+ currentPage === page ? "pagination-item-active" : ""
79
79
  }`}
80
80
  >
81
81
  {page}
@@ -93,7 +93,7 @@ const Pagination = ({
93
93
  onPageChange(newStart);
94
94
  }
95
95
  }}
96
- className="px-2 py-8 cursor-pointer disabled:opacity-40"
96
+ className="pagination-btn"
97
97
  >
98
98
  <span className="material-symbols-outlined">keyboard_arrow_right</span>
99
99
  </button>
@@ -6,12 +6,12 @@ import { useGSAP } from "@gsap/react";
6
6
 
7
7
  const Tab = ({
8
8
  tabs,
9
- tabClass = "w-full bg-[var(--background-wrapper)] border-b border-[var(--color-border)] relative z-0 h-[57px]",
10
- tabNavItemClass = "p-4",
11
- tabNavItemActiveClass = "bg-[var(--background-card)] border border-[var(--color-border)] border-b-[var(--background-card)] relative z-10",
9
+ tabClass = "tab",
10
+ tabNavItemClass = "tab-nav-item",
11
+ tabNavItemActiveClass = "tab-nav-item-active",
12
12
  tabContents,
13
- tabContentClass = "p-4 border border-t-0 border-[var(--color-border)] -mt-[1px]",
14
- tabContentItem = "text-[var(--text-standard)]",
13
+ tabContentClass = "tab-content",
14
+ tabContentItem = "tab-content-item",
15
15
  expectionValue,
16
16
  expectionLayout,
17
17
  }: {
@@ -76,7 +76,7 @@ const Tab = ({
76
76
  }, [activeContent]);
77
77
 
78
78
  return (
79
- <div className="flex flex-col">
79
+ <div className="flex flex-col w-full">
80
80
  <div className={tabClass}>
81
81
  {tabs.map((tab) => {
82
82
  return (
@@ -84,9 +84,9 @@ const Tab = ({
84
84
  key={tab.id}
85
85
  id={tab.id}
86
86
  onClick={() => handleTabActive(tab.target, tab.id)}
87
- className={`cursor-pointer ${tabNavItemClass} ${
87
+ className={`${tabNavItemClass} ${
88
88
  activeTab == tab.id
89
- ? `text-primary ${tabNavItemActiveClass}`
89
+ ? tabNavItemActiveClass
90
90
  : ""
91
91
  }`}
92
92
  >
@@ -101,8 +101,8 @@ const Tab = ({
101
101
  <div
102
102
  key={tabContent.id}
103
103
  id={tabContent.tag}
104
- className={`w-full sm:w-auto ${tabContentItem} ${
105
- activeTab == expectionValue ? expectionLayout : null
104
+ className={`${tabContentItem} ${
105
+ activeTab == expectionValue ? expectionLayout : ""
106
106
  }`}
107
107
  >
108
108
  {tabContent.content}
@@ -6,8 +6,8 @@ const Table = ({ tableData }: { tableData: Record<string, any>[] }) => {
6
6
  // tableData가 제공되지 않았거나 비어있는 경우, 데이터 없음 메시지를 표시합니다.
7
7
  if (!tableData || tableData.length === 0) {
8
8
  return (
9
- <div className="p-4 text-center">
10
- <p className="text-[var(--text-standard)]">표시할 데이터가 없습니다.</p>
9
+ <div className="table-empty">
10
+ <p>표시할 데이터가 없습니다.</p>
11
11
  </div>
12
12
  );
13
13
  }
@@ -15,17 +15,14 @@ const Table = ({ tableData }: { tableData: Record<string, any>[] }) => {
15
15
  const headers = Object.keys(tableData[0]);
16
16
 
17
17
  return (
18
- <div className="overflow-auto w-full">
19
- <table className="min-w-full border border-[var(--color-border)] rounded]">
20
- <thead className="bg-[var(--table-header-background)]">
18
+ <div className="table-container">
19
+ <table className="table">
20
+ <thead className="table-header">
21
21
  <tr>
22
22
  {/* 헤더 배열을 순회하며 각 헤더에 대한 <th>태그를 생성합니다. */}
23
23
  {headers.map((header, index) => {
24
24
  return (
25
- <th
26
- key={index}
27
- className="px-6 py-3 text-center text-[var(--table-header-text)] tracking-wider border-b border-[var(--color-border)]"
28
- >
25
+ <th key={index}>
29
26
  {header}
30
27
  </th>
31
28
  );
@@ -33,20 +30,14 @@ const Table = ({ tableData }: { tableData: Record<string, any>[] }) => {
33
30
  </tr>
34
31
  </thead>
35
32
  {/* 테이블 바디 부분 */}
36
- <tbody className={`divide-y divide-[var(--color-border)] `}>
33
+ <tbody className="table-body">
37
34
  {/* tableData 배열을 순회하며 각 데이터 객체(행)에 대한 <tr> 태그를 생성합니다. */}
38
35
  {tableData.map((row, rowIndex) => {
39
36
  return (
40
- <tr
41
- key={rowIndex}
42
- className={` ${rowIndex % 2 === 0 ? `bg-[var(--table-body-background)]` : `bg-[var(--table-body-background-even)]`}`}
43
- >
37
+ <tr key={rowIndex} className="table-row">
44
38
  {/* 각 행 내에서 헤더 배열을 다시 순회하며 해당 헤더에 맞는 셀(<td>)을 생성합니다. */}
45
39
  {headers.map((header, colIndex) => (
46
- <td
47
- key={colIndex} // 고유한 키를 제공합니다.
48
- className={`px-4 py-2 text-[var(--text-body-text)] border-b border-[var(--color-border)]`}
49
- >
40
+ <td key={colIndex} className="table-cell">
50
41
  {/* 현재 행 객체(row)에서 해당 헤더(키)에 해당하는 값을 가져와 셀에 표시합니다. */}
51
42
  {row[header]}
52
43
  </td>
@@ -1,118 +1,125 @@
1
1
  "use client";
2
2
 
3
3
  import { useEffect, useState } from "react";
4
- import { Radio } from "../Input/Input";
4
+ import { Radio } from "../Form/Form";
5
+ import { themes } from "@/build/typescript/theme";
6
+ import { Button } from "../Button/Button";
7
+ import { ModalContent } from "../Modal/Modal";
5
8
 
6
- export const ThemeSelector = ({
7
- type,
8
- }: {
9
- type: "all" | "theme" | "input";
10
- }) => {
11
- const themes = ["light", "dark"];
12
- const [selectedTheme, setSelectedTheme] = useState<string | null>("light");
13
- // const inputThemes = ["inputStandard", "inputCircle"];
14
- // const [selectedInputTheme, setSelectedInputTheme] = useState<string | null>(
15
- // null
16
- // );
9
+ export const ThemeSelector = () => {
10
+ const [selectedThemes, setSelectedThemes] = useState<Record<string, string>>({});
11
+ const [tempThemes, setTempThemes] = useState<Record<string, string>>({});
17
12
  const [isThemeLoading, setThemeLoading] = useState(false);
13
+ const [isModalOpen, setIsModalOpen] = useState(false);
18
14
 
19
15
  useEffect(() => {
20
16
  const chageThemeValue = () => {
21
- const storedTheme = localStorage.getItem("theme") || "light";
22
- // const storedInputTheme =
23
- // localStorage.getItem("inputTheme") || "inputStandard";
24
-
25
- setSelectedTheme(storedTheme);
26
- // setSelectedInputTheme(storedInputTheme);
17
+ const newThemes: Record<string, string> = {};
18
+ Object.entries(themes).forEach(([group, groupThemes]) => {
19
+ const storedKey = group === "global" ? "theme" : `theme-${group}`;
20
+ const storedTheme = localStorage.getItem(storedKey) || groupThemes[0];
21
+ newThemes[group] = storedTheme;
22
+ });
23
+ setSelectedThemes(newThemes);
24
+ setTempThemes(newThemes);
27
25
  };
28
26
 
29
27
  chageThemeValue();
30
28
  setThemeLoading(true);
31
29
  }, []);
32
30
 
33
- // main theme
34
- const handleThemeChange = (theme: string) => {
31
+ const handleTempThemeChange = (group: string, theme: string) => {
32
+ setTempThemes((prev) => ({ ...prev, [group]: theme }));
33
+ };
34
+
35
+ const handleApply = () => {
35
36
  if (typeof window !== "undefined") {
36
- localStorage.setItem("theme", theme);
37
+ Object.entries(tempThemes).forEach(([group, theme]) => {
38
+ const storedKey = group === "global" ? "theme" : `theme-${group}`;
39
+ localStorage.setItem(storedKey, theme);
40
+ });
37
41
  window.dispatchEvent(new Event("storage"));
38
- setSelectedTheme(theme);
42
+ setSelectedThemes(tempThemes);
43
+ setIsModalOpen(false);
39
44
  }
40
45
  };
41
- // input theme
42
- // const handleInputThemeChange = (theme: string) => {
43
- // if (typeof window !== "undefined") {
44
- // localStorage.setItem("inputTheme", theme);
45
- // window.dispatchEvent(new Event("storage"));
46
- // setSelectedInputTheme(theme);
47
- // }
48
- // };
49
- if (isThemeLoading == false) {
46
+
47
+ const handleOpenModal = () => {
48
+ setTempThemes(selectedThemes); // Reset to current applied themes
49
+ setIsModalOpen(true);
50
+ };
51
+
52
+ if (isThemeLoading === false) {
50
53
  return null;
51
54
  }
52
55
 
53
56
  return (
54
- <div className="flex flex-col gap-4">
55
- <p>theme 선택</p>
56
- <div className="flex flex-col gap-4">
57
- {type == "all" || type == "theme" ? (
58
- <div className="flex gap-4">
59
- {themes.map((theme) => (
60
- <Radio
61
- name="mainTheme"
62
- value={theme}
63
- key={theme}
64
- onChange={() => handleThemeChange(theme)}
65
- defaultChecked={theme == selectedTheme}
66
- />
67
- ))}
57
+ <>
58
+ <Button type="primary" onClick={handleOpenModal} style={{ width: "100%" }}>
59
+ <div className="flex items-center justify-center gap-2">
60
+ <span className="material-symbols-outlined" style={{ fontSize: "18px" }}>palette</span>
61
+ <span>테마 설정</span>
62
+ </div>
63
+ </Button>
64
+ <ModalContent
65
+ isOpen={isModalOpen}
66
+ onRequestClose={() => setIsModalOpen(false)}
67
+ modalTitle="테마 설정"
68
+ modalFooter={
69
+ <div className="flex justify-end gap-2 w-full mt-4">
70
+ <Button type="gray" onClick={() => setIsModalOpen(false)}>취소</Button>
71
+ <Button type="primary" onClick={handleApply}>적용</Button>
68
72
  </div>
69
- ) : null}
70
- {/* {type == "all" || type == "input" ? (
71
- <div className="flex gap-4">
72
- {inputThemes.map((inputTheme) => (
73
- <Radio
74
- name="inputTheme"
75
- value={inputTheme}
76
- key={inputTheme}
77
- onChange={() => handleInputThemeChange(inputTheme)}
78
- defaultChecked={inputTheme == selectedInputTheme}
79
- />
80
- ))}
81
- </div>
82
- ) : null} */}
83
- </div>
84
- </div>
73
+ }
74
+ >
75
+ <div className="flex flex-col gap-6 p-4">
76
+ {Object.entries(themes).map(([group, groupThemes]) => (
77
+ <div key={group} className="flex flex-col gap-3">
78
+ <p className="font-bold capitalize">{group} Theme</p>
79
+ <div className="flex gap-4 flex-wrap">
80
+ {groupThemes.map((theme) => (
81
+ <Radio
82
+ name={`theme-${group}-modal`}
83
+ value={theme}
84
+ key={theme}
85
+ onChange={() => handleTempThemeChange(group, theme)}
86
+ checked={theme === tempThemes[group]}
87
+ />
88
+ ))}
89
+ </div>
90
+ </div>
91
+ ))}
92
+ </div>
93
+ </ModalContent>
94
+ </>
85
95
  );
86
96
  };
87
97
 
88
- export const ThemeWrapper = ({
89
- children,
90
- className,
91
- }: {
92
- children: React.ReactNode;
93
- className: string;
94
- }) => {
95
- const [theme, setTheme] = useState<string | null>(null); // 테마 상태 추가
96
- const [inputTheme, setInputTheme] = useState<string | null>(null); // 테마 상태 추가
98
+ export const ThemeProvider = () => {
99
+ const [theme, setTheme] = useState<Record<string, string>>({});
97
100
  const [isThemeLoading, setThemeLoading] = useState(false);
98
- // theme setting
101
+
99
102
  useEffect(() => {
100
- // 로컬 스토리지에서 테마 가져오기
101
103
  const listenStorageChange = () => {
102
- setTheme(localStorage.getItem("theme") || "light");
103
- setInputTheme(localStorage.getItem("inputTheme") || "inputStandard");
104
-
105
- document.body.className = `${className} ${theme} ${inputTheme}`;
104
+ const newThemes: Record<string, string> = {};
105
+ Object.entries(themes).forEach(([group, groupThemes]) => {
106
+ const storedKey = group === "global" ? "theme" : `theme-${group}`;
107
+ const currentTheme = localStorage.getItem(storedKey) || groupThemes[0];
108
+ newThemes[group] = currentTheme;
109
+
110
+ document.documentElement.classList.remove(...groupThemes);
111
+ document.documentElement.classList.add(currentTheme);
112
+ });
113
+ setTheme(newThemes);
106
114
  };
115
+
107
116
  listenStorageChange();
108
117
  window.addEventListener("storage", listenStorageChange);
109
118
  setThemeLoading(true);
110
119
  return () => window.removeEventListener("storage", listenStorageChange);
111
- }, [theme]);
120
+ }, []);
112
121
 
113
- if (isThemeLoading == false) {
122
+ if (isThemeLoading === false) {
114
123
  return null;
115
124
  }
116
-
117
- return <>{children}</>;
118
125
  };