mirror of
https://github.com/Radiquum/AniX.git
synced 2025-09-05 22:15:36 +05:00
anix/feat: add filters modal with country, category, genre and lists exclusion filters
This commit is contained in:
parent
d3b198c6bc
commit
777fb5b82b
9 changed files with 396 additions and 18 deletions
|
@ -288,13 +288,6 @@ export function minutesToTime(min: number) {
|
||||||
if (minutes > 0) return minuteDisplay;
|
if (minutes > 0) return minuteDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatusList: Record<string, null | number> = {
|
|
||||||
last: null,
|
|
||||||
finished: 1,
|
|
||||||
ongoing: 2,
|
|
||||||
announce: 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const FilterCountry = ["Япония", "Китай", "Южная Корея"];
|
export const FilterCountry = ["Япония", "Китай", "Южная Корея"];
|
||||||
export const FilterCategoryIdToString: Record<number, string> = {
|
export const FilterCategoryIdToString: Record<number, string> = {
|
||||||
1: "Сериал",
|
1: "Сериал",
|
||||||
|
|
124
app/components/Discovery/Modal/FiltersGenreModal.tsx
Normal file
124
app/components/Discovery/Modal/FiltersGenreModal.tsx
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { FilterGenre } from "#/api/utils";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
Label,
|
||||||
|
Modal,
|
||||||
|
ModalBody,
|
||||||
|
ModalFooter,
|
||||||
|
ModalHeader,
|
||||||
|
ToggleSwitch,
|
||||||
|
} from "flowbite-react";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isOpen: boolean;
|
||||||
|
setIsOpen: (isOpen: boolean) => void;
|
||||||
|
genres: string[];
|
||||||
|
exclusionMode: boolean;
|
||||||
|
save: (genres, exclusionMode) => void;
|
||||||
|
};
|
||||||
|
export const FiltersGenreModal = ({
|
||||||
|
isOpen,
|
||||||
|
setIsOpen,
|
||||||
|
genres,
|
||||||
|
exclusionMode,
|
||||||
|
save,
|
||||||
|
}: Props) => {
|
||||||
|
const [newGenres, setNewGenres] = useState(genres);
|
||||||
|
const [newExclusionMode, setNewExclusionMode] = useState(exclusionMode);
|
||||||
|
|
||||||
|
function toggleGenre(string: string) {
|
||||||
|
if (newGenres.includes(string)) {
|
||||||
|
setNewGenres(newGenres.filter((genre) => genre != string));
|
||||||
|
} else {
|
||||||
|
setNewGenres([...newGenres, string]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setNewGenres(genres);
|
||||||
|
setNewExclusionMode(exclusionMode);
|
||||||
|
}, [genres, exclusionMode]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal show={isOpen} onClose={() => setIsOpen(false)} dismissible>
|
||||||
|
<ModalHeader>Жанры</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<div>
|
||||||
|
{Object.entries(FilterGenre).map(([key, value]) => {
|
||||||
|
return (
|
||||||
|
<div key={`filter-genre-category-${value.name}`} className="mb-4">
|
||||||
|
<p className="mb-2">{value.name}</p>
|
||||||
|
{value.genres.map((genre) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
key={`filter-genre-category-${value.name}-${genre}`}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
id={`filter-genre-category-${value.name}-genre-${genre}`}
|
||||||
|
onChange={() => toggleGenre(genre)}
|
||||||
|
checked={newGenres.includes(genre)}
|
||||||
|
color="blue"
|
||||||
|
/>
|
||||||
|
<Label
|
||||||
|
htmlFor={`filter-genre-category-${value.name}-genre-${genre}`}
|
||||||
|
>
|
||||||
|
{genre}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<div className="flex justify-between w-full">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div>
|
||||||
|
<p className="mb-1 font-bold">Режим исключения</p>
|
||||||
|
<p className="text-sm text-gray-400 dark:text-gray-300 max-w-52">
|
||||||
|
Фильтр будет искать релизы не содержащие ни один из указанных
|
||||||
|
выше жанров
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<ToggleSwitch
|
||||||
|
color="blue"
|
||||||
|
onChange={() => setNewExclusionMode(!newExclusionMode)}
|
||||||
|
checked={newExclusionMode}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
save([], false);
|
||||||
|
setNewGenres([]);
|
||||||
|
setNewExclusionMode(false);
|
||||||
|
setIsOpen(false);
|
||||||
|
}}
|
||||||
|
color="red"
|
||||||
|
>
|
||||||
|
Сбросить
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
save(newGenres, newExclusionMode);
|
||||||
|
setNewGenres([]);
|
||||||
|
setNewExclusionMode(false);
|
||||||
|
setIsOpen(false);
|
||||||
|
}}
|
||||||
|
color="blue"
|
||||||
|
>
|
||||||
|
Применить
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalFooter>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
87
app/components/Discovery/Modal/FiltersListExcludeModal.tsx
Normal file
87
app/components/Discovery/Modal/FiltersListExcludeModal.tsx
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { FilterProfileListIdToString } from "#/api/utils";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
Label,
|
||||||
|
Modal,
|
||||||
|
ModalBody,
|
||||||
|
ModalFooter,
|
||||||
|
ModalHeader
|
||||||
|
} from "flowbite-react";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isOpen: boolean;
|
||||||
|
setIsOpen: (isOpen: boolean) => void;
|
||||||
|
lists: number[];
|
||||||
|
setLists: (lists: number[]) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FiltersListExcludeModal = ({
|
||||||
|
isOpen,
|
||||||
|
setIsOpen,
|
||||||
|
lists,
|
||||||
|
setLists,
|
||||||
|
}: Props) => {
|
||||||
|
const [newList, setNewList] = useState(lists);
|
||||||
|
|
||||||
|
function toggleList(number: number) {
|
||||||
|
if (newList.includes(number)) {
|
||||||
|
setNewList(newList.filter((list) => list != number));
|
||||||
|
} else {
|
||||||
|
setNewList([...newList, number]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setNewList(lists);
|
||||||
|
}, [lists]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal show={isOpen} onClose={() => setIsOpen(false)} dismissible>
|
||||||
|
<ModalHeader>Выберите списки</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
{Object.entries(FilterProfileListIdToString).map(([key, value]) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
key={`filter-list-exclude-${value}`}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
id={`filter-list-exclude-${value}`}
|
||||||
|
onChange={() => toggleList(Number(key))}
|
||||||
|
checked={newList.includes(Number(key))}
|
||||||
|
color="blue"
|
||||||
|
/>
|
||||||
|
<Label htmlFor={`filter-list-exclude-${value}`}>{value}</Label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setLists([]);
|
||||||
|
setNewList([]);
|
||||||
|
setIsOpen(false);
|
||||||
|
}}
|
||||||
|
color="red"
|
||||||
|
>
|
||||||
|
Сбросить
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setLists(newList);
|
||||||
|
setNewList([]);
|
||||||
|
setIsOpen(false);
|
||||||
|
}}
|
||||||
|
color="blue"
|
||||||
|
>
|
||||||
|
Применить
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
172
app/components/Discovery/Modal/FiltersModal.tsx
Normal file
172
app/components/Discovery/Modal/FiltersModal.tsx
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Filter,
|
||||||
|
FilterCategoryIdToString,
|
||||||
|
FilterCountry,
|
||||||
|
FilterDefault,
|
||||||
|
FilterProfileListIdToString,
|
||||||
|
} from "#/api/utils";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Dropdown,
|
||||||
|
DropdownItem,
|
||||||
|
Modal,
|
||||||
|
ModalBody,
|
||||||
|
ModalFooter,
|
||||||
|
ModalHeader,
|
||||||
|
} from "flowbite-react";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { FiltersGenreModal } from "./FiltersGenreModal";
|
||||||
|
import { useUserStore } from "#/store/auth";
|
||||||
|
import { FiltersListExcludeModal } from "./FiltersListExcludeModal";
|
||||||
|
|
||||||
|
type ModalProps = {
|
||||||
|
isOpen: boolean;
|
||||||
|
setIsOpen: (value: boolean) => void;
|
||||||
|
filter?: Filter;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FiltersModal = ({ isOpen, setIsOpen, filter }: ModalProps) => {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
const [newFilter, setNewFilter] = useState(filter || FilterDefault);
|
||||||
|
const [isGenreModalOpen, setIsGenreModalOpen] = useState(false);
|
||||||
|
const [isListExcludeModalOpen, setIsListExcludeModalOpen] = useState(false);
|
||||||
|
|
||||||
|
function saveGenres(genres, is_genres_exclude_mode_enabled) {
|
||||||
|
setNewFilter({ ...newFilter, genres, is_genres_exclude_mode_enabled });
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Modal
|
||||||
|
// show={isOpen}
|
||||||
|
show={true}
|
||||||
|
onClose={() => setIsOpen(false)}
|
||||||
|
size="4xl"
|
||||||
|
dismissible
|
||||||
|
>
|
||||||
|
<ModalHeader>Фильтр</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<p>Страна</p>
|
||||||
|
<Dropdown
|
||||||
|
label={newFilter.country || "Неважно"}
|
||||||
|
color="blue"
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
<DropdownItem
|
||||||
|
key={`filter-modal-country-none`}
|
||||||
|
onClick={() => setNewFilter({ ...newFilter, country: null })}
|
||||||
|
>
|
||||||
|
Неважно
|
||||||
|
</DropdownItem>
|
||||||
|
{FilterCountry.map((item) => {
|
||||||
|
return (
|
||||||
|
<DropdownItem
|
||||||
|
key={`filter-modal-country-${item}`}
|
||||||
|
onClick={() =>
|
||||||
|
setNewFilter({ ...newFilter, country: item })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</DropdownItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<p>Категория</p>
|
||||||
|
<Dropdown
|
||||||
|
label={
|
||||||
|
newFilter.category_id ?
|
||||||
|
FilterCategoryIdToString[newFilter.category_id]
|
||||||
|
: "Неважно"
|
||||||
|
}
|
||||||
|
color="blue"
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
<DropdownItem
|
||||||
|
key={`filter-modal-category-none`}
|
||||||
|
onClick={() =>
|
||||||
|
setNewFilter({ ...newFilter, category_id: null })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Неважно
|
||||||
|
</DropdownItem>
|
||||||
|
{Object.entries(FilterCategoryIdToString).map(
|
||||||
|
([key, value]) => {
|
||||||
|
return (
|
||||||
|
<DropdownItem
|
||||||
|
key={`filter-modal-category-${key}`}
|
||||||
|
onClick={() =>
|
||||||
|
setNewFilter({
|
||||||
|
...newFilter,
|
||||||
|
category_id: Number(key),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</DropdownItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<p>Жанры</p>
|
||||||
|
<Button
|
||||||
|
color={"blue"}
|
||||||
|
className="w-full min-h-10 h-fit"
|
||||||
|
onClick={() => setIsGenreModalOpen(true)}
|
||||||
|
>
|
||||||
|
{newFilter.genres.length > 0 ?
|
||||||
|
newFilter.genres.join(", ")
|
||||||
|
: "Неважно"}
|
||||||
|
</Button>
|
||||||
|
<p className="text-sm">
|
||||||
|
Будет искать релизы, содержащие каждый из указанных жанров.
|
||||||
|
Рекомендуется выбирать не более 3 жанров
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{userStore.isAuth ? <div className="space-y-2">
|
||||||
|
<p>Исключить закладки</p>
|
||||||
|
<Button
|
||||||
|
color={"blue"}
|
||||||
|
className="w-full min-h-10 h-fit"
|
||||||
|
onClick={() => setIsListExcludeModalOpen(true)}
|
||||||
|
>
|
||||||
|
{newFilter.profile_list_exclusions.length > 0 ?
|
||||||
|
newFilter.profile_list_exclusions
|
||||||
|
.map((id) => FilterProfileListIdToString[id])
|
||||||
|
.join(", ")
|
||||||
|
: "Неважно"}
|
||||||
|
</Button>
|
||||||
|
<p className="text-sm">
|
||||||
|
Исключит из выдачи релизы, входящие в указанные закладки
|
||||||
|
</p>
|
||||||
|
</div> : ""}
|
||||||
|
</div>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter></ModalFooter>
|
||||||
|
</Modal>
|
||||||
|
<FiltersGenreModal
|
||||||
|
isOpen={isGenreModalOpen}
|
||||||
|
setIsOpen={setIsGenreModalOpen}
|
||||||
|
genres={newFilter.genres}
|
||||||
|
exclusionMode={newFilter.is_genres_exclude_mode_enabled}
|
||||||
|
save={saveGenres}
|
||||||
|
/>
|
||||||
|
<FiltersListExcludeModal
|
||||||
|
isOpen={isListExcludeModalOpen}
|
||||||
|
setIsOpen={setIsListExcludeModalOpen}
|
||||||
|
lists={newFilter.profile_list_exclusions}
|
||||||
|
setLists={(profile_list_exclusions) =>
|
||||||
|
setNewFilter({ ...newFilter, profile_list_exclusions })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -69,7 +69,7 @@ export const NavBarMobile = (props: { setIsSettingModalOpen: any }) => {
|
||||||
<footer className="fixed bottom-0 left-0 right-0 z-50 block w-full h-[70px] font-medium text-white bg-black rounded-t-lg lg:hidden">
|
<footer className="fixed bottom-0 left-0 right-0 z-50 block w-full h-[70px] font-medium text-white bg-black rounded-t-lg lg:hidden">
|
||||||
<div className="flex items-center justify-center h-full gap-4">
|
<div className="flex items-center justify-center h-full gap-4">
|
||||||
{NavbarItems.map((item) => {
|
{NavbarItems.map((item) => {
|
||||||
if (item.auth && !userStore.isAuth) return <></>;
|
if (item.auth && !userStore.isAuth) return;
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
href={item.href}
|
href={item.href}
|
||||||
|
@ -90,7 +90,7 @@ export const NavBarMobile = (props: { setIsSettingModalOpen: any }) => {
|
||||||
<></>
|
<></>
|
||||||
: <Link
|
: <Link
|
||||||
href={FifthButton[preferenceStore.flags.showFifthButton].href}
|
href={FifthButton[preferenceStore.flags.showFifthButton].href}
|
||||||
key={`navbar-mobile-${FifthButton[preferenceStore.flags.showFifthButton].title}`}
|
key={`navbar-mobile-fifthbutton-${FifthButton[preferenceStore.flags.showFifthButton].title}`}
|
||||||
className="flex flex-col items-center justify-center gap-1"
|
className="flex flex-col items-center justify-center gap-1"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
@ -133,9 +133,8 @@ export const NavBarMobile = (props: { setIsSettingModalOpen: any }) => {
|
||||||
<span className="ml-2">Профиль</span>
|
<span className="ml-2">Профиль</span>
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
{Object.entries(FifthButton).map(([key, item]) => {
|
{Object.entries(FifthButton).map(([key, item]) => {
|
||||||
if (item.auth && !userStore.isAuth) return <></>;
|
if (item.auth && !userStore.isAuth) return;
|
||||||
if (preferenceStore.flags.showFifthButton === key)
|
if (preferenceStore.flags.showFifthButton === key) return;
|
||||||
return <></>;
|
|
||||||
return (
|
return (
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
key={`navbar-mobile-${item.title}`}
|
key={`navbar-mobile-${item.title}`}
|
||||||
|
|
|
@ -65,7 +65,7 @@ export const NavBarPc = (props: { setIsSettingModalOpen: any }) => {
|
||||||
<div className="container flex items-center justify-between h-full px-2 mx-auto">
|
<div className="container flex items-center justify-between h-full px-2 mx-auto">
|
||||||
<div className="flex items-center h-full gap-3">
|
<div className="flex items-center h-full gap-3">
|
||||||
{NavbarItems.map((item) => {
|
{NavbarItems.map((item) => {
|
||||||
if (item.auth && !userStore.isAuth) return <></>;
|
if (item.auth && !userStore.isAuth) return;
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
href={item.href}
|
href={item.href}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { CollectionsOfTheWeek } from "#/components/Discovery/CollectionsOfTheWeek";
|
import { CollectionsOfTheWeek } from "#/components/Discovery/CollectionsOfTheWeek";
|
||||||
import { DiscussingToday } from "#/components/Discovery/DiscussingToday";
|
import { DiscussingToday } from "#/components/Discovery/DiscussingToday";
|
||||||
import { InterestingCarousel } from "#/components/Discovery/InterestingCarousel";
|
import { InterestingCarousel } from "#/components/Discovery/InterestingCarousel";
|
||||||
|
import { FiltersModal } from "#/components/Discovery/Modal/FiltersModal";
|
||||||
import { PopularModal } from "#/components/Discovery/Modal/PopularModal";
|
import { PopularModal } from "#/components/Discovery/Modal/PopularModal";
|
||||||
import { ScheduleModal } from "#/components/Discovery/Modal/ScheduleModal";
|
import { ScheduleModal } from "#/components/Discovery/Modal/ScheduleModal";
|
||||||
import { RecommendedCarousel } from "#/components/Discovery/RecommendedCarousel";
|
import { RecommendedCarousel } from "#/components/Discovery/RecommendedCarousel";
|
||||||
|
@ -14,6 +15,7 @@ export const DiscoverPage = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [PopularModalOpen, setPopularModalOpen] = useState(false);
|
const [PopularModalOpen, setPopularModalOpen] = useState(false);
|
||||||
const [ScheduleModalOpen, setScheduleModalOpen] = useState(false);
|
const [ScheduleModalOpen, setScheduleModalOpen] = useState(false);
|
||||||
|
const [FiltersModalOpen, setFiltersModalOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -58,6 +60,7 @@ export const DiscoverPage = () => {
|
||||||
isOpen={ScheduleModalOpen}
|
isOpen={ScheduleModalOpen}
|
||||||
setIsOpen={setScheduleModalOpen}
|
setIsOpen={setScheduleModalOpen}
|
||||||
/>
|
/>
|
||||||
|
<FiltersModal isOpen={FiltersModalOpen} setIsOpen={setFiltersModalOpen} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
8
package-lock.json
generated
8
package-lock.json
generated
|
@ -12,7 +12,7 @@
|
||||||
"apexcharts": "^3.52.0",
|
"apexcharts": "^3.52.0",
|
||||||
"deepmerge-ts": "^7.1.0",
|
"deepmerge-ts": "^7.1.0",
|
||||||
"flowbite": "^2.4.1",
|
"flowbite": "^2.4.1",
|
||||||
"flowbite-react": "^0.11.7",
|
"flowbite-react": "^0.12.7",
|
||||||
"hls-video-element": "^1.5.0",
|
"hls-video-element": "^1.5.0",
|
||||||
"markdown-to-jsx": "^7.4.7",
|
"markdown-to-jsx": "^7.4.7",
|
||||||
"media-chrome": "^4.9.0",
|
"media-chrome": "^4.9.0",
|
||||||
|
@ -3348,9 +3348,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/flowbite-react": {
|
"node_modules/flowbite-react": {
|
||||||
"version": "0.11.7",
|
"version": "0.12.7",
|
||||||
"resolved": "https://registry.npmjs.org/flowbite-react/-/flowbite-react-0.11.7.tgz",
|
"resolved": "https://registry.npmjs.org/flowbite-react/-/flowbite-react-0.12.7.tgz",
|
||||||
"integrity": "sha512-Z8m+ycHEsXPacSAi8P4yYDeff7LvcHNwbGAnL/+Fpiv+6ZWDEAGY/YPKhUofZsZa837JTYrbcbmgjqQ1bpt51g==",
|
"integrity": "sha512-d8GR7mnCfdIl4n5RXxz4dKin6DIEA7Ax9mXDpJhz9gwxaPKUklKJZKtQ+KkdmFNrB65Zy76Pam01yr3LcxlseA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/core": "1.6.9",
|
"@floating-ui/core": "1.6.9",
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
"apexcharts": "^3.52.0",
|
"apexcharts": "^3.52.0",
|
||||||
"deepmerge-ts": "^7.1.0",
|
"deepmerge-ts": "^7.1.0",
|
||||||
"flowbite": "^2.4.1",
|
"flowbite": "^2.4.1",
|
||||||
"flowbite-react": "^0.11.7",
|
"flowbite-react": "^0.12.7",
|
||||||
"hls-video-element": "^1.5.0",
|
"hls-video-element": "^1.5.0",
|
||||||
"markdown-to-jsx": "^7.4.7",
|
"markdown-to-jsx": "^7.4.7",
|
||||||
"media-chrome": "^4.9.0",
|
"media-chrome": "^4.9.0",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue