diff --git a/.flowbite-react/config.json b/.flowbite-react/config.json index 3ebc21b..d04ad92 100644 --- a/.flowbite-react/config.json +++ b/.flowbite-react/config.json @@ -2,9 +2,8 @@ "$schema": "https://unpkg.com/flowbite-react/schema.json", "components": [], "dark": true, - "path": "src/components", "prefix": "", - "rsc": true, + "path": "src/components", "tsx": true, - "version": 3 + "rsc": true } \ No newline at end of file diff --git a/.flowbite-react/init.tsx b/.flowbite-react/init.tsx deleted file mode 100644 index 43ac927..0000000 --- a/.flowbite-react/init.tsx +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -// @ts-nocheck -// biome-ignore-all lint: auto-generated file - -// This file is auto-generated by the flowbite-react CLI. -// Do not edit this file directly. -// Instead, edit the .flowbite-react/config.json file. - -import { StoreInit } from "flowbite-react/store/init"; -import React from "react"; - -export const CONFIG = { - dark: true, - prefix: "", - version: 3, -}; - -export function ThemeInit() { - return ; -} - -ThemeInit.displayName = "ThemeInit"; \ No newline at end of file diff --git a/api-prox/index.ts b/api-prox/index.ts index 2f399f0..98856c1 100644 --- a/api-prox/index.ts +++ b/api-prox/index.ts @@ -226,9 +226,7 @@ app.get("/*path", async (req, res) => { if ( !apiResponse || !apiResponse.ok || - (apiResponse.headers.get("content-type") != "application/json" && - apiResponse.headers.get("content-type") != - "application/json;charset=UTF-8") + apiResponse.headers.get("content-type") != "application/json" ) { logger.error( `Failed to fetch: '${url.protocol}//${url.hostname}${url.pathname}', Path probably doesn't exist` @@ -279,7 +277,7 @@ app.post("/*path", async (req, res) => { "application/json", "application/x-www-form-urlencoded", "multipart/form-data", - "x-unknown/unknown", + "x-unknown/unknown" ]; const isSupported = supportedContentTypes.includes( @@ -337,9 +335,7 @@ app.post("/*path", async (req, res) => { if ( !apiResponse || !apiResponse.ok || - (apiResponse.headers.get("content-type") != "application/json" && - apiResponse.headers.get("content-type") != - "application/json;charset=UTF-8") + apiResponse.headers.get("content-type") != "application/json" ) { logger.error( `Failed to post: '${url.protocol}//${url.hostname}${url.pathname}', Path probably doesn't exist` diff --git a/app/App.tsx b/app/App.tsx index eaf472a..8cccbd0 100644 --- a/app/App.tsx +++ b/app/App.tsx @@ -1,6 +1,7 @@ "use client"; import { useUserStore } from "./store/auth"; import { usePreferencesStore } from "./store/preferences"; +import { Navbar } from "./components/Navbar/NavbarUpdate"; import { Inter } from "next/font/google"; import { useEffect, useState } from "react"; import { @@ -13,9 +14,6 @@ import { import { Spinner } from "./components/Spinner/Spinner"; import { ChangelogModal } from "#/components/ChangelogModal/ChangelogModal"; import { Bounce, ToastContainer } from "react-toastify"; -import { NavBarPc } from "./components/Navbar/NavBarPc"; -import { NavBarMobile } from "./components/Navbar/NavBarMobile"; -import { SettingsModal } from "./components/SettingsModal/SettingsModal"; const inter = Inter({ subsets: ["latin"] }); @@ -25,7 +23,6 @@ export const App = (props) => { const [showChangelog, setShowChangelog] = useState(false); const [currentVersion, setCurrentVersion] = useState(""); const [previousVersions, setPreviousVersions] = useState([]); - const [isSettingModalOpen, setIsSettingModalOpen] = useState(false); useEffect(() => { async function _checkVersion() { @@ -71,8 +68,8 @@ export const App = (props) => { - -
+ +
{props.children}
{ theme="colored" transition={Bounce} /> - - ); }; diff --git a/app/api/config.ts b/app/api/config.ts index f406316..316d19e 100644 --- a/app/api/config.ts +++ b/app/api/config.ts @@ -1,4 +1,4 @@ -export const CURRENT_APP_VERSION = "3.9.0"; +export const CURRENT_APP_VERSION = "3.8.0"; import { env } from "next-runtime-env"; const NEXT_PUBLIC_API_URL = env("NEXT_PUBLIC_API_URL") || null; @@ -51,7 +51,6 @@ export const ENDPOINTS = { } }, filter: `${API_PREFIX}/filter`, - filterTypes: `${API_PREFIX}/type/all`, search: { profileList: `${API_PREFIX}/search/profile/list`, profileHistory: `${API_PREFIX}/search/history`, @@ -75,13 +74,5 @@ export const ENDPOINTS = { releaseInCollections: `${API_PREFIX}/collection/all/release`, userCollections: `${API_PREFIX}/collection/all/profile`, favoriteCollections: `${API_PREFIX}/collectionFavorite`, - }, - discover: { - interesting: `${API_PREFIX}/discover/interesting`, - discussing: `${API_PREFIX}/discover/discussing`, - watching: `${API_PREFIX}/discover/watching`, - recommendations: `${API_PREFIX}/discover/recommendations`, - collections: `${API_PREFIX}/collection/all`, - schedule: `${API_PREFIX}/schedule`, } }; diff --git a/app/api/utils.ts b/app/api/utils.ts index a3e6907..fabc2b7 100644 --- a/app/api/utils.ts +++ b/app/api/utils.ts @@ -248,519 +248,99 @@ export function sinceUnixDate(unixInSeconds: number) { ); } -export function minutesToTime(min: number) { - const seconds = min * 60; - const epoch = new Date(0); - const date = new Date(seconds * 1000); +export function minutesToTime( + min: number, + type?: "full" | "daysOnly" | "daysHours" +) { + const d = Math.floor(min / 1440); // 60*24 + const h = Math.floor((min - d * 1440) / 60); + const m = Math.round(min % 60); - const diffInMinutes = - new Date(date.getTime() - epoch.getTime()).getTime() / 1000 / 60; + var dDisplay = + d > 0 ? `${d} ${numberDeclension(d, "день", "дня", "дней")}` : ""; + var hDisplay = + h > 0 ? `${h} ${numberDeclension(h, "час", "часа", "часов")}` : ""; + var mDisplay = + m > 0 ? `${m} ${numberDeclension(m, "минута", "минуты", "минут")}` : ""; - let days = Math.floor(diffInMinutes / 1440); - if (days < 0) days = 0; - const daysToMinutes = days * 1440; - - let hours = Math.floor((diffInMinutes - daysToMinutes) / 60); - if (hours < 0) hours = 0; - const hoursToMinutes = hours * 60; - - let minutes = diffInMinutes - daysToMinutes - hoursToMinutes; - if (minutes < 0) minutes = 0; - - const dayDisplay = - days > 0 ? `${days} ${numberDeclension(days, "день", "дня", "дней")}` : ""; - const hourDisplay = - hours > 0 ? - `${hours} ${numberDeclension(hours, "час", "часа", "часов")}` - : ""; - const minuteDisplay = - minutes > 0 ? - `${minutes} ${numberDeclension(minutes, "минута", "минуты", "минут")}` - : ""; - - if (days > 0 && hours > 0 && minutes > 0) - return `${dayDisplay}, ${hourDisplay}, ${minuteDisplay}`; - if (days > 0 && hours > 0) return `${dayDisplay}, ${hourDisplay}`; - if (days > 0 && minutes > 0) return `${dayDisplay}, ${minuteDisplay}`; - if (hours > 0 && minutes > 0) return `${hourDisplay}, ${minuteDisplay}`; - if (days > 0) return dayDisplay; - if (hours > 0) return hourDisplay; - if (minutes > 0) return minuteDisplay; + if (type == "daysOnly") { + if (d > 0) return dDisplay; + return "? дней"; + } else if (type == "daysHours") { + if (d > 0 && h > 0) return dDisplay + ", " + hDisplay; + if (h > 0) return hDisplay; + if (m > 0) return mDisplay; + } else { + return `${d > 0 ? dDisplay : ""}${h > 0 ? ", " + hDisplay : ""}${m > 0 ? ", " + mDisplay : ""}`; + } } -export const FilterCountry = ["Япония", "Китай", "Южная Корея"]; -export const FilterCategoryIdToString: Record = { - 1: "Сериал", - 2: "Полнометражный фильм", - 3: "OVA", - 4: "Дорама", +const StatusList: Record = { + last: null, + finished: 1, + ongoing: 2, + announce: 3, }; -export const FilterGenre = { - uncategorized: { - name: "Нет категории", - genres: [ - "авангард", - "гурман", - "драма", - "комедия", - "повседневность", - "приключения", - "романтика", - "сверхъестественное", - "спорт", - "тайна", - "триллер", - "ужасы", - "фантастика", - "фэнтези", - "экшен", - "эротика", - "этти", - ], - }, - audience: { - name: "Аудитория", - genres: [ - "детское", - "дзёсей", - "сэйнэн", - "сёдзё", - "сёдзё-ай", - "сёнен", - "сёнен-ай", - ], - }, - theme: { - name: "Тематика", - genres: [ - "CGDCT", - "антропоморфизм", - "боевые искусства", - "вампиры", - "взрослые персонажи", - "видеоигры", - "военное", - "выживание", - "гарем", - "гонки", - "городское фэнтези", - "гэг-юмор", - "детектив", - "жестокость", - "забота о детях", - "злодейка", - "игра с высокими ставками", - "идолы (жен.)", - "идолы (муж.)", - "изобразительное искусство", - "исполнительское искусство", - "исторический", - "исэкай", - "иясикэй", - "командный спорт", - "космос", - "кроссдрессинг", - "культура отаку", - "любовный многоугольник", - "магическая смена пола", - "махо-сёдзё", - "медицина", - "меха", - "мифология", - "музыка", - "образовательное", - "организованная преступность", - "пародия", - "питомцы", - "психологическое", - "путешествие во времени", - "работа", - "реверс-гарем", - "реинкарнация", - "романтический подтекст", - "самураи", - "спортивные единоборства", - "стратегические игры", - "супер сила", - "удостоено наград", - "хулиганы", - "школа", - "шоу-бизнес", - ], - }, -}; -export const FilterProfileListIdToString: Record = { - 0: "Избранное", - 1: "Смотрю", - 2: "В планах", - 3: "Просмотрено", - 4: "Отложено", - 5: "Брошено", -}; -export const FilterStudio = [ - "A-1 Pictures", - "A.C.G.T", - "ACTAS, Inc", - "ACiD FiLM", - "AIC A.S.T.A", - "AIC PLUS", - "AIC Spirits", - "AIC", - "Animac", - "ANIMATE", - "Aniplex", - "ARMS", - "Artland", - "ARTMIC Studios", - "Asahi Production", - "Asia-Do", - "ASHI", - "Asread", - "Asmik Ace", - "Aubeck", - "BM Entertainment", - "Bandai Visua", - "Barnum Studio", - "Bee Train", - "BeSTACK", - "Blender Foundation", - "Bones", - "Brains Base", - "Bridge", - "Cinema Citrus", - "Chaos Project", - "Cherry Lips", - "David Production", - "Daume", - "Doumu", - "Dax International", - "DLE INC", - "Digital Frontier", - "Digital Works", - "Diomedea", - "DIRECTIONS Inc", - "Dogakobo", - "Dofus", - "Encourage Films", - "Feel", - "Fifth Avenue", - "Five Ways", - "Fuji TV", - "Foursome", - "GRAM Studio", - "G&G Entertainment", - "Gainax", - "GANSIS", - "Gathering", - "Gonzino", - "Gonzo", - "GoHands", - "Green Bunny", - "Group TAC", - "Hal Film Maker", - "Hasbro Studios", - "h.m.p", - "Himajin", - "Hoods Entertainment", - "Idea Factory", - "J.C.Staff", - "KANSAI", - "Kaname Production", - "Kitty Films", - "Knack", - "Kokusai Eigasha", - "KSS (студия)", - "Kyoto Animation", - "Lemon Heart", - "LMD", - "Madhouse Studios", - "Magic Bus", - "Manglobe Inc.", - "Manpuku Jinja", - "MAPPA", - "Milky", - "Minamimachi Bugyosho", - "Media Blasters", - "Mook Animation", - "Moonrock", - "MOVIC", - "Mushi Productions", - "Natural High", - "Nippon Animation", - "Nomad", - "Lerche", - "OB Planning", - "Office AO", - "Ordet", - "Oriental Light and Magic", - "OLM Inc.", - "P.A. Works", - "Palm Studio", - "Pastel", - "Phoenix Entertainment", - "Picture Magic", - "Pink", - "Pink Pineapple", - "Planet", - "Plum", - "PPM", - "Primastea", - "Production I.G", - "Project No.9", - "Radix", - "Rikuentai", - "Robot", - "Satelight", - "Seven", - "Seven Arcs", - "Shaft", - "Silver Link", - "Shinei Animation", - "Shogakukan Music & Digital Entertainment", - "Soft on Demand", - "Starchild Records", - "Studio 9 Maiami", - "Studio Tulip", - "Studio 4°C", - "Studio e.go!", - "Studio A.P.P.P", - "Studio Barcelona", - "Studio Blanc", - "Studio Comet", - "Studio Deen", - "Studio Fantasia", - "Studio Flag", - "Studio Gallop", - "Studio Ghibli", - "Studio Guts", - "Studio Gokumi", - "Studio Rikka", - "Studio Hibari", - "Studio Junio", - "Studio Khara", - "Studio Live", - "Studio Matrix", - "Studio Pierrot", - "Studio Egg", - "Sunrise", - "Synergy SP", - "Synergy Japan", - "Tatsunoko Production", - "Tele-Cartoon Japan", - "Telecom Animation Film", - "Tezuka Productions", - "The Answer Studio", - "TMS", - "TNK", - "Toei Animation", - "Tokyo Kids", - "TYO Animations", - "Transarts", - "Triangle Staff", - "Trinet Entertainment", - "Ufotable", - "Vega Entertainment", - "Victor Entertainment", - "Viewworks", - "White Fox", - "Wonder Farm", - "XEBEC-M2", - "Xebec", - "Yumeta Company", - "Zexcs", - "Zuiyo Eizo", - "8bit", -]; -export const FilterSource = [ - "Оригинал", - "Манга", - "Веб-манга", - "Енкома", - "Ранобэ", - "Новелла", - "Веб-новелла", - "Визуальная новелла", - "Игра", - "Карточная игра", - "Книга", - "Книга с картинками", - "Музыка", - "Радио", - "Более одного", - "Другое", -]; -export const FilterYear = Array.from({ length: 200 }, (_, i) => 1900 + i); // 1900-2100 years around now -export const FilterSeasonIdToString = { - 1: "Зима", - 2: "Весна", - 3: "Лето", - 4: "Осень", -}; -export const FilterEpisodeCount = [ - { - name: "Неважно", - episodes_from: null, - episodes_to: null, - }, - { - name: "От 1 до 12", - episodes_from: 1, - episodes_to: 12, - }, - { - name: "От 13 до 25", - episodes_from: 13, - episodes_to: 25, - }, - { - name: "От 26 до 100", - episodes_from: 26, - episodes_to: 100, - }, - { - name: "Больше 100", - episodes_from: 100, - episodes_to: null, - }, -]; -export const FilterEpisodeDuration = [ - { - name: "Неважно", + +export async function _FetchHomePageReleases( + status: string, + token: string | null, + page: string | number = 0 +) { + let statusId: null | number = null; + let categoryId: null | number = null; + if (status == "films") { + categoryId = 2; + } else { + statusId = StatusList[status]; + } + + const body = { + country: null, + season: null, + sort: 0, + studio: null, + age_ratings: [], + category_id: categoryId, + end_year: null, episode_duration_from: null, episode_duration_to: null, - }, - { - name: "До 10 минут", - episode_duration_from: 1, - episode_duration_to: 10, - }, - { - name: "До 30 минут", - episode_duration_from: 1, - episode_duration_to: 30, - }, - { - name: "Более 30 минут", - episode_duration_from: 30, - episode_duration_to: null, - }, -]; -export const FilterStatusIdToString = { - 1: "Вышел", - 2: "Выходит", - 3: "Анонс", -}; -export const FilterAgeRatingToString = { - 1: "0+", - 2: "6+", - 3: "12+", - 4: "16+", - 5: "18+", -}; -export const FilterSortToString = { - 0: "По дате добавления", - 1: "По рейтингу", - 2: "По годам", - 3: "По популярности", -}; + episodes_from: null, + episodes_to: null, + genres: [], + profile_list_exclusions: [], + start_year: null, + status_id: statusId, + types: [], + is_genres_exclude_mode_enabled: false, + }; -export type Filter = { - country: null | string; - category_id: null | number; - genres: string[]; - is_genres_exclude_mode_enabled: boolean; - profile_list_exclusions: number[]; - types: number[]; // fetched from /type/all - studio: null | string; - source: null | string; - start_year: null | number; - end_year: null | number; - season: null | number; - episodes_from: null | number; - episodes_to: null | number; - episode_duration_from: null | number; - episode_duration_to: null | number; - status_id: null | number; - age_ratings: number[]; - sort: number; -}; - -export const FilterDefault: Filter = { - country: null, - season: null, - sort: 0, - source: null, - studio: null, - age_ratings: [], - category_id: null, - end_year: null, - episode_duration_from: null, - episode_duration_to: null, - episodes_from: null, - episodes_to: null, - genres: [], - is_genres_exclude_mode_enabled: false, - profile_list_exclusions: [], - start_year: null, - status_id: null, - types: [], -}; - -export async function FetchFilter( - { - country, - category_id, - genres, - is_genres_exclude_mode_enabled, - profile_list_exclusions, - types, - studio, - source, - start_year, - end_year, - season, - episodes_from, - episodes_to, - episode_duration_from, - episode_duration_to, - status_id, - age_ratings, - sort, - }: Filter, - page: number, - token: null | string -) { let url: string; url = `${ENDPOINTS.filter}/${page}`; if (token) { url += `?token=${token}`; } - const { data, error } = await fetchDataViaPost( - url, - JSON.stringify({ - country, - category_id, - genres, - is_genres_exclude_mode_enabled, - profile_list_exclusions, - types, - studio, - source, - start_year, - end_year, - season, - episodes_from, - episodes_to, - episode_duration_from, - episode_duration_to, - status_id, - age_ratings, - sort, + const data: Object = fetch(url, { + method: "POST", + headers: HEADERS, + body: JSON.stringify(body), + }) + .then((response) => { + if (response.ok) { + return response.json(); + } else { + throw new Error("Error fetching data"); + } }) - ); - - return [data, error]; + .then((data: Object) => { + return data; + }) + .catch((error) => { + console.log(error); + return null; + }); + return data; } export const BookmarksList = { diff --git a/app/components/CollectionCourusel/CollectionCourusel.module.css b/app/components/CollectionCourusel/CollectionCourusel.module.css index 1f56115..fce52de 100644 --- a/app/components/CollectionCourusel/CollectionCourusel.module.css +++ b/app/components/CollectionCourusel/CollectionCourusel.module.css @@ -6,12 +6,6 @@ display: none !important; } -@media (hover: hover) and (min-width: 1024px) { - .swiper { - overflow: visible !important; - } -} - @media (hover: hover) { .section:hover .swiper-button { display: flex !important; diff --git a/app/components/CollectionCourusel/CollectionCourusel.tsx b/app/components/CollectionCourusel/CollectionCourusel.tsx index e53bcd8..c3b920e 100644 --- a/app/components/CollectionCourusel/CollectionCourusel.tsx +++ b/app/components/CollectionCourusel/CollectionCourusel.tsx @@ -55,7 +55,7 @@ export const CollectionCourusel = (props: { )}
-
+
{props.isMyCollections && (
diff --git a/app/components/CollectionLink/CollectionLink.tsx b/app/components/CollectionLink/CollectionLink.tsx index a7887d1..aee2010 100644 --- a/app/components/CollectionLink/CollectionLink.tsx +++ b/app/components/CollectionLink/CollectionLink.tsx @@ -5,43 +5,60 @@ import Image from "next/image"; export const CollectionLink = (props: any) => { return ( -
- {""} -
-
- +
+ {props.title - {props.comment_count && ( +
- )} - {props.is_private && ( -
- + {props.comment_count && ( + + )} + {props.is_private && ( +
+ +
+ )} + {props.is_favorite && ( +
+ +
+ )} +
+
+
+

+ {props.title} +

- )} - {props.is_favorite && ( -
- -
- )} -
-
-

- {props.title} -

-

- {props.description} -

+ {props.description && ( +

+ {`${props.description.slice(0, 125)}${ + props.description.length > 125 ? "..." : "" + }`} +

+ )} +
diff --git a/app/components/CollectionsSection/CollectionsSection.tsx b/app/components/CollectionsSection/CollectionsSection.tsx index 6e03911..c7b0775 100644 --- a/app/components/CollectionsSection/CollectionsSection.tsx +++ b/app/components/CollectionsSection/CollectionsSection.tsx @@ -16,7 +16,7 @@ export const CollectionsSection = (props: {
)}
-
+
{props.isMyCollections && } {props.content.map((collection) => { return ( @@ -25,6 +25,7 @@ export const CollectionsSection = (props: {
); })} + {props.content.length == 1 && !props.isMyCollections &&
}
diff --git a/app/components/Discovery/CollectionsOfTheWeek.tsx b/app/components/Discovery/CollectionsOfTheWeek.tsx deleted file mode 100644 index cec280a..0000000 --- a/app/components/Discovery/CollectionsOfTheWeek.tsx +++ /dev/null @@ -1,31 +0,0 @@ -"use client"; - -import { ENDPOINTS } from "#/api/config"; -import { useSWRfetcher } from "#/api/utils"; -import useSWR from "swr"; -import { CollectionCourusel } from "../CollectionCourusel/CollectionCourusel"; -import { useUserStore } from "#/store/auth"; - -export const CollectionsOfTheWeek = () => { - const token = useUserStore((state) => state.token); - const { data, isLoading, error } = useSWR( - `${ENDPOINTS.discover.collections}/-1?previous_page=0&where=2&sort=4${token ? `&token=${token}` : ""}`, - useSWRfetcher, - { - revalidateOnFocus: false, - revalidateIfStale: false, - revalidateOnReconnect: false, - } - ); - - if (error) return <>; - if (isLoading) return <>; - - return ( - - ); -}; diff --git a/app/components/Discovery/DiscussingToday.tsx b/app/components/Discovery/DiscussingToday.tsx deleted file mode 100644 index 948273b..0000000 --- a/app/components/Discovery/DiscussingToday.tsx +++ /dev/null @@ -1,50 +0,0 @@ -"use client"; - -import { ENDPOINTS } from "#/api/config"; -import { useSWRfetcher } from "#/api/utils"; -import { useUserStore } from "#/store/auth"; -import Link from "next/link"; -import { PosterWithStuff } from "../ReleasePoster/PosterWithStuff"; -import useSWR from "swr"; - -export const DiscussingToday = () => { - const token = useUserStore((state) => state.token); - const { data, isLoading, error } = useSWR( - `${ENDPOINTS.discover.discussing}${token ? `?token=${token}` : ""}`, - useSWRfetcher, - { - revalidateOnFocus: false, - revalidateIfStale: false, - revalidateOnReconnect: false, - } - ); - - if (error) return <>; - if (isLoading) return <>; - - return ( -
-
-

- Обсуждаемое сегодня -

-
-
- {data.content.map((item) => { - return ( - - - - ); - })} -
-
- ); -}; diff --git a/app/components/Discovery/InterestingCarousel.module.css b/app/components/Discovery/InterestingCarousel.module.css deleted file mode 100644 index ed205c5..0000000 --- a/app/components/Discovery/InterestingCarousel.module.css +++ /dev/null @@ -1,21 +0,0 @@ -.swiper-button:global(.swiper-button-disabled) { - opacity: 0 !important; -} - -.swiper-button { - display: none !important; -} - -@media (hover: hover) and (min-width: 1024px) { - .swiper { - overflow: visible !important; - } -} - -@media (hover: hover) { - .swiper:hover .swiper-button { - display: flex !important; - width: 64px; - height: 64px; - } -} diff --git a/app/components/Discovery/InterestingCarousel.tsx b/app/components/Discovery/InterestingCarousel.tsx deleted file mode 100644 index fa4e366..0000000 --- a/app/components/Discovery/InterestingCarousel.tsx +++ /dev/null @@ -1,78 +0,0 @@ -"use client"; - -import { ENDPOINTS } from "#/api/config"; -import { useSWRfetcher } from "#/api/utils"; -import useSWR from "swr"; -import Image from "next/image"; -import { Swiper, SwiperSlide } from "swiper/react"; -import "swiper/css"; -import "swiper/css/navigation"; -import { Navigation } from "swiper/modules"; -import Styles from "./InterestingCarousel.module.css"; -import Link from "next/link"; - -export const InterestingCarousel = () => { - const { data, isLoading, error } = useSWR( - ENDPOINTS.discover.interesting, - useSWRfetcher, - { - revalidateOnFocus: false, - revalidateIfStale: false, - revalidateOnReconnect: false, - } - ); - - if (error) return <>; - if (isLoading) return <>; - - return ( -
- - {data.content.map((item) => { - return ( - - -
- -
-
-

{item.title}

-

{item.description}

-
-
- -
- ); - })} -
-
-
-
- ); -}; diff --git a/app/components/Discovery/Modal/FiltersAgeRatingModal.tsx b/app/components/Discovery/Modal/FiltersAgeRatingModal.tsx deleted file mode 100644 index 167a2fe..0000000 --- a/app/components/Discovery/Modal/FiltersAgeRatingModal.tsx +++ /dev/null @@ -1,106 +0,0 @@ -"use client"; - -import { FilterAgeRatingToString } 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; - ageRatings: number[]; - setAgeRatings: (lists: number[]) => void; -}; - -export const FiltersAgeRatingModal = ({ - isOpen, - setIsOpen, - ageRatings, - setAgeRatings, -}: Props) => { - const [newAgeRatings, setNewAgeRatings] = useState(ageRatings); - - function toggleRating(number: number) { - if (newAgeRatings.includes(number)) { - setNewAgeRatings(newAgeRatings.filter((rating) => rating != number)); - } else { - setNewAgeRatings([...newAgeRatings, number]); - } - } - - useEffect(() => { - setNewAgeRatings(ageRatings); - }, [ageRatings]); - - return ( - setIsOpen(false)} dismissible> - Выберите списки - - {Object.entries(FilterAgeRatingToString).map(([key, value]) => { - return ( -
- toggleRating(Number(key))} - checked={newAgeRatings.includes(Number(key))} - color="blue" - /> - -
- ); - })} -
- - - - - -
- ); -}; diff --git a/app/components/Discovery/Modal/FiltersGenreModal.tsx b/app/components/Discovery/Modal/FiltersGenreModal.tsx deleted file mode 100644 index 7ee4362..0000000 --- a/app/components/Discovery/Modal/FiltersGenreModal.tsx +++ /dev/null @@ -1,141 +0,0 @@ -"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); - - const genresLength = - FilterGenre.uncategorized.genres.length + - FilterGenre.audience.genres.length + - FilterGenre.theme.genres.length; - - 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 ( - setIsOpen(false)} dismissible size="6xl"> - Жанры - -
- {Object.entries(FilterGenre).map(([key, value]) => { - return ( -
-

{value.name}

- {value.genres.map((genre) => { - return ( -
- toggleGenre(genre)} - checked={newGenres.includes(genre)} - color="blue" - /> - -
- ); - })} -
- ); - })} -
-
- -
-
-
-

Режим исключения

-

- Фильтр будет искать релизы не содержащие ни один из указанных - выше жанров -

-
- setNewExclusionMode(!newExclusionMode)} - checked={newExclusionMode} - /> -
-
- - - -
-
-
-
- ); -}; diff --git a/app/components/Discovery/Modal/FiltersListExcludeModal.tsx b/app/components/Discovery/Modal/FiltersListExcludeModal.tsx deleted file mode 100644 index 4c72cf4..0000000 --- a/app/components/Discovery/Modal/FiltersListExcludeModal.tsx +++ /dev/null @@ -1,107 +0,0 @@ -"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 ( - setIsOpen(false)} dismissible> - Выберите списки - - {Object.entries(FilterProfileListIdToString).map(([key, value]) => { - return ( -
- toggleList(Number(key))} - checked={newList.includes(Number(key))} - color="blue" - /> - -
- ); - })} -
- - - - - -
- ); -}; diff --git a/app/components/Discovery/Modal/FiltersModal.tsx b/app/components/Discovery/Modal/FiltersModal.tsx deleted file mode 100644 index f65aa4e..0000000 --- a/app/components/Discovery/Modal/FiltersModal.tsx +++ /dev/null @@ -1,565 +0,0 @@ -"use client"; - -import { - Filter, - FilterAgeRatingToString, - FilterCategoryIdToString, - FilterCountry, - FilterDefault, - FilterEpisodeCount, - FilterEpisodeDuration, - FilterProfileListIdToString, - FilterSeasonIdToString, - FilterSortToString, - FilterSource, - FilterStatusIdToString, - FilterStudio, - FilterYear, - tryCatchAPI, -} from "#/api/utils"; -import { - Button, - Dropdown, - DropdownItem, - Modal, - ModalBody, - ModalFooter, - ModalHeader, -} from "flowbite-react"; -import { useEffect, useState } from "react"; -import { FiltersGenreModal } from "./FiltersGenreModal"; -import { useUserStore } from "#/store/auth"; -import { FiltersListExcludeModal } from "./FiltersListExcludeModal"; -import { ENDPOINTS } from "#/api/config"; -import { FiltersTypesModal } from "./FiltersTypesModal"; -import { FiltersAgeRatingModal } from "./FiltersAgeRatingModal"; -import { useRouter } from "next/navigation"; - -type ModalProps = { - isOpen: boolean; - setIsOpen: (value: boolean) => void; - filter?: Filter; - setFilter?: (filter: Filter) => void; -}; - -export const FiltersModal = ({ - isOpen, - setIsOpen, - filter, - setFilter, -}: ModalProps) => { - const userStore = useUserStore(); - const router = useRouter(); - - const [newFilter, setNewFilter] = useState(filter || FilterDefault); - const [isGenreModalOpen, setIsGenreModalOpen] = useState(false); - const [isListExcludeModalOpen, setIsListExcludeModalOpen] = useState(false); - const [isTypeModalOpen, setIsTypeModalOpen] = useState(false); - const [isAgeRatingModalOpen, setIsAgeRatingModalOpen] = useState(false); - - const [types, setTypes] = useState([]); - const [error, setError] = useState(null); - - useEffect(() => { - const fetchData = async () => { - setError(null); - - const { data, error } = await tryCatchAPI(fetch(ENDPOINTS.filterTypes)); - - if (error) { - setError(error); - } else { - setTypes(data.types); - } - }; - fetchData(); - }, []); - - function saveGenres(genres, is_genres_exclude_mode_enabled) { - setNewFilter({ ...newFilter, genres, is_genres_exclude_mode_enabled }); - } - - function saveFilter() { - const _filter = JSON.stringify(newFilter); - if (setFilter) { - setFilter(newFilter); - } else { - router.push(`/discovery/filter?filter=${_filter}`); - } - setIsOpen(false); - } - - return ( - <> - setIsOpen(false)} - size="4xl" - dismissible - > - Фильтр - -
-
-

Страна

- - setNewFilter({ ...newFilter, country: null })} - > - Неважно - - {FilterCountry.map((item) => { - return ( - - setNewFilter({ ...newFilter, country: item }) - } - > - {item} - - ); - })} - -
-
-

Категория

- - - setNewFilter({ ...newFilter, category_id: null }) - } - > - Неважно - - {Object.entries(FilterCategoryIdToString).map( - ([key, value]) => { - return ( - - setNewFilter({ - ...newFilter, - category_id: Number(key), - }) - } - > - {value} - - ); - } - )} - -
-
-

Жанры

- -

- Будет искать релизы, содержащие каждый из указанных жанров. - Рекомендуется выбирать не более 3 жанров -

-
- {userStore.isAuth ? -
-

Исключить закладки

- -

- Исключит из выдачи релизы, входящие в указанные закладки -

-
- : ""} -
-

Варианты озвучек

- -
-
-

Студия

- - setNewFilter({ ...newFilter, studio: null })} - > - Неважно - - {FilterStudio.map((value) => { - return ( - - setNewFilter({ - ...newFilter, - studio: value, - }) - } - > - {value} - - ); - })} - -
-
-

Первоисточник

- - setNewFilter({ ...newFilter, source: null })} - > - Неважно - - {FilterSource.map((value) => { - return ( - - setNewFilter({ - ...newFilter, - source: value, - }) - } - > - {value} - - ); - })} - -
-
-

Года

-
-

С

- - - setNewFilter({ ...newFilter, start_year: null }) - } - > - Неважно - - {FilterYear.map((value) => { - return ( - - setNewFilter({ - ...newFilter, - start_year: value, - }) - } - > - {value} - - ); - })} - -

По

- - - setNewFilter({ ...newFilter, end_year: null }) - } - > - Неважно - - {FilterYear.map((value) => { - return ( - - setNewFilter({ - ...newFilter, - end_year: value, - }) - } - > - {value} - - ); - })} - -

Сезон

- - setNewFilter({ ...newFilter, season: null })} - > - Неважно - - {Object.entries(FilterSeasonIdToString).map( - ([key, value]) => { - return ( - - setNewFilter({ - ...newFilter, - season: Number(key), - }) - } - > - {value} - - ); - } - )} - -
-
-
-
-
-

Эпизодов

- - episode.episodes_from === newFilter.episodes_from && - episode.episodes_to === newFilter.episodes_to - ).name - } - color="blue" - className="w-full overflow-y-auto max-h-64" - > - {FilterEpisodeCount.map((value) => { - return ( - - setNewFilter({ - ...newFilter, - episodes_from: value.episodes_from, - episodes_to: value.episodes_to, - }) - } - > - {value.name} - - ); - })} - -
-
-

Длительность эпизода

- - episode.episode_duration_from === - newFilter.episode_duration_from && - episode.episode_duration_to === - newFilter.episode_duration_to - ).name - } - color="blue" - className="w-full overflow-y-auto max-h-64" - > - {FilterEpisodeDuration.map((value) => { - return ( - - setNewFilter({ - ...newFilter, - episode_duration_from: - value.episode_duration_from, - episode_duration_to: value.episode_duration_to, - }) - } - > - {value.name} - - ); - })} - -
-
-

Статус

- - - setNewFilter({ ...newFilter, status_id: null }) - } - > - Неважно - - {Object.entries(FilterStatusIdToString).map( - ([key, value]) => { - return ( - - setNewFilter({ - ...newFilter, - status_id: Number(key), - }) - } - > - {value} - - ); - } - )} - -
-
-
-
-

Возрастное ограничение

- -
-
-

Сортировка

- - {Object.entries(FilterSortToString).map(([key, value]) => { - return ( - - setNewFilter({ - ...newFilter, - sort: Number(key), - }) - } - > - {value} - - ); - })} - -
-
-
- - - -
- - - setNewFilter({ ...newFilter, profile_list_exclusions }) - } - /> - setNewFilter({ ...newFilter, types })} - /> - - setNewFilter({ ...newFilter, age_ratings }) - } - /> - - ); -}; diff --git a/app/components/Discovery/Modal/FiltersTypesModal.tsx b/app/components/Discovery/Modal/FiltersTypesModal.tsx deleted file mode 100644 index 80b50bb..0000000 --- a/app/components/Discovery/Modal/FiltersTypesModal.tsx +++ /dev/null @@ -1,100 +0,0 @@ -"use client"; - -import { - Button, - Checkbox, - Label, - Modal, - ModalBody, - ModalFooter, - ModalHeader, -} from "flowbite-react"; -import { useEffect, useState } from "react"; - -type Props = { - isOpen: boolean; - setIsOpen: (isOpen: boolean) => void; - typesData: any[]; - types: number[]; - setTypes: (types: number[]) => void; -}; - -export const FiltersTypesModal = ({ - isOpen, - setIsOpen, - typesData, - types, - setTypes, -}: Props) => { - const [newTypes, setNewTypes] = useState(types); - - function toggleType(number: number) { - if (newTypes.includes(number)) { - setNewTypes(newTypes.filter((list) => list != number)); - } else { - setNewTypes([...newTypes, number]); - } - } - - useEffect(() => { - setNewTypes(types); - }, [types]); - - return ( - setIsOpen(false)} dismissible> - Выберите списки - - {typesData.map((item) => { - return ( -
- toggleType(Number(item.id))} - checked={newTypes.includes(Number(item.id))} - color="blue" - /> - -
- ); - })} -
- - - - - -
- ); -}; diff --git a/app/components/Discovery/Modal/PopularFilters.ts b/app/components/Discovery/Modal/PopularFilters.ts deleted file mode 100644 index 82d0948..0000000 --- a/app/components/Discovery/Modal/PopularFilters.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { FilterDefault } from "#/api/utils"; - -export const TabOngoing = { - id: "ongoing", - name: "Онгоинги", - filter: { - ...FilterDefault, - sort: 3, - episodes_from: 1, - episodes_to: 48, - status_id: 2, - }, -}; - -export const TabFinished = { - id: "finished", - name: "Завершённые", - filter: { ...FilterDefault, sort: 3, status_id: 1 }, -}; - -export const TabFilms = { - id: "films", - name: "Фильмы", - filter: { ...FilterDefault, sort: 3, category_id: 2 }, -}; - -export const TabOVA = { - id: "ova", - name: "OVA", - filter: { ...FilterDefault, sort: 3, category_id: 3 }, -}; - -export const tabs = [TabOngoing, TabFinished, TabFilms, TabOVA]; -export const tabsId = { ongoing: 0, finished: 1, films: 2, ova: 3 }; diff --git a/app/components/Discovery/Modal/PopularModal.tsx b/app/components/Discovery/Modal/PopularModal.tsx deleted file mode 100644 index 36616ab..0000000 --- a/app/components/Discovery/Modal/PopularModal.tsx +++ /dev/null @@ -1,82 +0,0 @@ -"use client"; - -import { ENDPOINTS } from "#/api/config"; -import { FetchFilter, useSWRfetcher } from "#/api/utils"; -import { useUserStore } from "#/store/auth"; -import useSWR from "swr"; - -import { tabs, tabsId } from "./PopularFilters"; -import { - Button, - ButtonGroup, - Modal, - ModalBody, - ModalHeader, -} from "flowbite-react"; -import { useEffect, useState } from "react"; -import { ReleaseLink } from "#/components/ReleaseLink/ReleaseLinkUpdate"; -import { Spinner } from "#/components/Spinner/Spinner"; -type ModalProps = { - isOpen: boolean; - setIsOpen: (value: boolean) => void; -}; - -export const PopularModal = ({ isOpen, setIsOpen }: ModalProps) => { - const token = useUserStore((state) => state.token); - const [tab, setTab] = useState< - "ongoing" | "finished" | "films" | "ova" | string - >("ongoing"); - const [content, setContent] = useState(null); - - useEffect(() => { - setContent(null); - async function _loadReleases() { - const [data, error] = await FetchFilter( - tabs[tabsId[tab]].filter, - 0, - token - ); - if (!error) { - setContent(data.content); - } - } - _loadReleases(); - }, [tab, token]); - - return ( - setIsOpen(false)} - size="7xl" - dismissible - > - Популярное - -
- - {tabs.map((item) => ( - - ))} - -
-
- {content ? - content.map((release) => { - return ( -
- -
- ); - }) - : } -
-
-
- ); -}; diff --git a/app/components/Discovery/Modal/ScheduleModal.tsx b/app/components/Discovery/Modal/ScheduleModal.tsx deleted file mode 100644 index 1b60d49..0000000 --- a/app/components/Discovery/Modal/ScheduleModal.tsx +++ /dev/null @@ -1,71 +0,0 @@ -"use client"; - -import { ENDPOINTS } from "#/api/config"; -import { useSWRfetcher } from "#/api/utils"; -import useSWR from "swr"; -import { Modal, ModalBody, ModalHeader } from "flowbite-react"; -import { Spinner } from "#/components/Spinner/Spinner"; -import { ReleaseCourusel } from "#/components/ReleaseCourusel/ReleaseCourusel"; -type ModalProps = { - isOpen: boolean; - setIsOpen: (value: boolean) => void; -}; - -export const ScheduleModal = ({ isOpen, setIsOpen }: ModalProps) => { - const { data, isLoading, error } = useSWR( - ENDPOINTS.discover.schedule, - useSWRfetcher, - { - revalidateOnFocus: false, - revalidateIfStale: false, - revalidateOnReconnect: false, - } - ); - - return ( - setIsOpen(false)} - size="7xl" - dismissible - > - Расписание - - {!error ? - isLoading ? -
- -
- :
- - - - - - - -
- - : "Ошибка загрузки"} -
-
- ); -}; diff --git a/app/components/Discovery/RecommendedCarousel.tsx b/app/components/Discovery/RecommendedCarousel.tsx deleted file mode 100644 index 5fa2949..0000000 --- a/app/components/Discovery/RecommendedCarousel.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client"; - -import { ENDPOINTS } from "#/api/config"; -import { useSWRfetcher } from "#/api/utils"; -import { useUserStore } from "#/store/auth"; -import { ReleaseCourusel } from "../ReleaseCourusel/ReleaseCourusel"; -import useSWR from "swr"; - -export const RecommendedCarousel = () => { - const token = useUserStore((state) => state.token); - const { data, isLoading, error } = useSWR( - token ? `${ENDPOINTS.discover.recommendations}/-1?previous_page=-1&token=${token}` : null, - useSWRfetcher, - { - revalidateOnFocus: false, - revalidateIfStale: false, - revalidateOnReconnect: false, - } - ); - - if (!token) return <>; - if (error) return <>; - if (isLoading) return <>; - - return ; -}; diff --git a/app/components/Discovery/WatchingNowCarousel.tsx b/app/components/Discovery/WatchingNowCarousel.tsx deleted file mode 100644 index 0bb20a1..0000000 --- a/app/components/Discovery/WatchingNowCarousel.tsx +++ /dev/null @@ -1,25 +0,0 @@ -"use client"; - -import { ENDPOINTS } from "#/api/config"; -import { useSWRfetcher } from "#/api/utils"; -import { useUserStore } from "#/store/auth"; -import { ReleaseCourusel } from "../ReleaseCourusel/ReleaseCourusel"; -import useSWR from "swr"; - -export const WatchingNowCarousel = () => { - const token = useUserStore((state) => state.token); - const { data, isLoading, error } = useSWR( - `${ENDPOINTS.discover.watching}/0${token ? `?token=${token}` : ""}`, - useSWRfetcher, - { - revalidateOnFocus: false, - revalidateIfStale: false, - revalidateOnReconnect: false, - } - ); - - if (error) return <>; - if (isLoading) return <>; - - return ; -}; diff --git a/app/components/Navbar/NavBarMobile.tsx b/app/components/Navbar/NavBarMobile.tsx deleted file mode 100644 index 6108483..0000000 --- a/app/components/Navbar/NavBarMobile.tsx +++ /dev/null @@ -1,175 +0,0 @@ -"use client"; -import { - Avatar, - Dropdown, - DropdownDivider, - DropdownItem, -} from "flowbite-react"; -import { useUserStore } from "#/store/auth"; -import Link from "next/link"; -import { usePathname, useRouter } from "next/navigation"; -import { usePreferencesStore } from "#/store/preferences"; - -const NavbarItems = [ - { - title: "Домашняя", - icon: "mdi--home", - href: "/", - auth: false, - }, - { - title: "Поиск", - icon: "mdi--search", - href: "/search", - auth: false, - }, - { - title: "Закладки", - icon: "mdi--bookmark-multiple", - href: "/bookmarks", - auth: true, - }, -]; - -const FifthButton = { - favorites: { - title: "Избранное", - icon: "mdi--favorite", - href: "/favorites", - auth: true, - }, - collections: { - title: "Коллекции", - icon: "mdi--collections-bookmark", - href: "/collections", - auth: true, - }, - history: { - title: "История", - icon: "mdi--history", - href: "/history", - auth: true, - }, - discovery: { - title: "Обзор", - icon: "mdi--compass", - href: "/discovery", - auth: false, - }, -}; - -export const NavBarMobile = (props: { setIsSettingModalOpen: any }) => { - const userStore = useUserStore(); - const router = useRouter(); - const pathname = usePathname(); - const preferenceStore = usePreferencesStore(); - - return ( - <> -
-
- {NavbarItems.map((item) => { - if (item.auth && !userStore.isAuth) return; - return ( - - - {item.title} - - ); - })} - {preferenceStore.flags.showFifthButton ? - <> - {( - !userStore.isAuth && - FifthButton[preferenceStore.flags.showFifthButton].auth - ) ? - <> - : - - - {FifthButton[preferenceStore.flags.showFifthButton].title} - - - } - - : ""} - - -

- {userStore.isAuth ? userStore.user.login : "Аноним"} -

-
- } - > - {userStore.isAuth && ( - <> - router.push(`/profile/${userStore.user.id}`)} - > - - Профиль - - {Object.entries(FifthButton).map(([key, item]) => { - if (item.auth && !userStore.isAuth) return; - if (preferenceStore.flags.showFifthButton === key) return; - return ( - router.push(item.href)} - > - - {item.title} - - ); - })} - - - )} - props.setIsSettingModalOpen(true)} - className="relative flex" - > - - Настройки - - {userStore.isAuth ? - userStore.logout()}> - - Выйти - - : router.push(`/login?redirect=${pathname}`)} - > - - Войти - - } - -
- - - ); -}; diff --git a/app/components/Navbar/NavBarPc.tsx b/app/components/Navbar/NavBarPc.tsx deleted file mode 100644 index 902a6ef..0000000 --- a/app/components/Navbar/NavBarPc.tsx +++ /dev/null @@ -1,139 +0,0 @@ -"use client"; -import { - Avatar, - Dropdown, - DropdownDivider, - DropdownItem, -} from "flowbite-react"; -import { useUserStore } from "#/store/auth"; -import Link from "next/link"; -import { usePathname, useRouter } from "next/navigation"; - -const NavbarItems = [ - { - title: "Домашняя", - icon: "mdi--home", - href: "/", - auth: false, - }, - { - title: "Обзор", - icon: "mdi--compass", - href: "/discovery", - auth: false, - }, - { - title: "Поиск", - icon: "mdi--search", - href: "/search", - auth: false, - }, - { - title: "Закладки", - icon: "mdi--bookmark-multiple", - href: "/bookmarks", - auth: true, - }, - { - title: "Избранное", - icon: "mdi--favorite", - href: "/favorites", - auth: true, - }, - { - title: "Коллекции", - icon: "mdi--collections-bookmark", - href: "/collections", - auth: true, - }, - { - title: "История", - icon: "mdi--history", - href: "/history", - auth: true, - }, -]; - -export const NavBarPc = (props: { setIsSettingModalOpen: any }) => { - const userStore = useUserStore(); - const router = useRouter(); - const pathname = usePathname(); - - return ( - <> -
-
-
- {NavbarItems.map((item) => { - if (item.auth && !userStore.isAuth) return; - return ( - - - {item.title} - - ); - })} -
- - -

- {userStore.isAuth ? userStore.user.login : "Аноним"} -

-
- } - > - {userStore.isAuth ? - router.push(`/profile/${userStore.user.id}`)} - className="relative flex" - > - - Профиль - - : ""} - props.setIsSettingModalOpen(true)} - className="relative flex" - > - - Настройки - - {userStore.isAuth ? - userStore.logout()} - className="relative flex" - > - - Выйти - - : router.push(`/login?redirect=${pathname}`)} - className="relative flex" - > - - Войти - - } - -
- - - ); -}; diff --git a/app/components/Navbar/NavbarUpdate.tsx b/app/components/Navbar/NavbarUpdate.tsx new file mode 100644 index 0000000..a6219c0 --- /dev/null +++ b/app/components/Navbar/NavbarUpdate.tsx @@ -0,0 +1,215 @@ +"use client"; + +import Link from "next/link"; +import Image from "next/image"; +import { useUserStore } from "#/store/auth"; +import { usePathname } from "next/navigation"; +import { useState } from "react"; +import { SettingsModal } from "#/components/SettingsModal/SettingsModal"; +import { usePreferencesStore } from "#/store/preferences"; + +export const Navbar = () => { + const pathname = usePathname(); + const userStore = useUserStore(); + const [isSettingModalOpen, setIsSettingModalOpen] = useState(false); + const preferenceStore = usePreferencesStore(); + + const menuItems = [ + { + id: 1, + title: "Домашняя", + href: "/", + hrefInCategory: "/home", + icon: { + default: "material-symbols--home-outline", + active: "material-symbols--home", + }, + isAuthRequired: false, + isShownOnMobile: true, + }, + { + id: 2, + title: "Поиск", + href: "/search", + icon: { + default: "material-symbols--search", + active: "material-symbols--search", + }, + isAuthRequired: false, + isShownOnMobile: true, + }, + { + id: 3, + title: "Закладки", + href: "/bookmarks", + icon: { + default: "material-symbols--bookmarks-outline", + active: "material-symbols--bookmarks", + }, + isAuthRequired: true, + isShownOnMobile: true, + }, + { + id: 4, + title: "Избранное", + href: "/favorites", + icon: { + default: "material-symbols--favorite-outline", + active: "material-symbols--favorite", + }, + isAuthRequired: true, + isShownOnMobile: false, + }, + { + id: 5, + title: "Коллекции", + href: "/collections", + icon: { + default: "material-symbols--collections-bookmark-outline", + active: "material-symbols--collections-bookmark", + }, + isAuthRequired: true, + isShownOnMobile: false, + }, + { + id: 6, + title: "История", + href: "/history", + icon: { + default: "material-symbols--history", + active: "material-symbols--history", + }, + isAuthRequired: true, + isShownOnMobile: false, + }, + ]; + + return ( + <> +
+
+
+ {menuItems.map((item) => { + return ( + + + + {item.title} + + + ); + })} +
+
+ {!userStore.isAuth ? + + + + Войти + + + : <> + + + + {userStore.user.login} + + + {preferenceStore.flags.showFifthButton ? + + + + {menuItems[preferenceStore.flags.showFifthButton].title} + + + : ""} + + + + {userStore.user.login} + + + + } + + {userStore.isAuth && ( + + )} +
+
+
+ + + ); +}; diff --git a/app/components/Profile/Profile.Stats.tsx b/app/components/Profile/Profile.Stats.tsx index 659ea91..214c1cb 100644 --- a/app/components/Profile/Profile.Stats.tsx +++ b/app/components/Profile/Profile.Stats.tsx @@ -3,21 +3,12 @@ import Link from "next/link"; import ApexCharts from "apexcharts"; import { useEffect } from "react"; import { minutesToTime } from "#/api/utils"; -import { ReleaseInfoSearchLink } from "../ReleaseInfo/ReleaseInfo.SearchLink"; - -type preferredItem = { - name: string; - percentage: number; -}; export const ProfileStats = (props: { lists: Array; watched_count: number; watched_time: number; - profile_id: number; - preferred_genres: Array; - preferred_audiences: Array; - preferred_themes: Array; + profile_id: number }) => { const getChartOptions = () => { return { @@ -90,95 +81,41 @@ export const ProfileStats = (props: {
-
-

- {" "} - Смотрю {props.lists[0]} -

-

- {" "} - В планах {props.lists[1]} -

-

- {" "} - Просмотрено {props.lists[2]} -

-

- {" "} - Отложено {props.lists[3]} -

-

- {" "} - Брошено {props.lists[4]} -

-
-
-

- Жанры:{" "} - - {props.preferred_genres.map((item, index) => { - return ( -

- {index > 0 && ", "} - {" "} - {item.percentage}% -
- ); - })} - -

-

- Аудитория:{" "} - - {props.preferred_audiences.map((item, index) => { - return ( -

- {index > 0 && ", "} - {" "} - {item.percentage}% -
- ); - })} - -

-

- Тематика:{" "} - - {props.preferred_themes.map((item, index) => { - return ( -

- {index > 0 && ", "} - {" "} - {item.percentage}% -
- ); - })} - -

- -

- Просмотрено серий:{" "} - {props.watched_count} -

-

- Время просмотра:{" "} - - ~{minutesToTime(props.watched_time)} - -

-
+

+ {" "} + Смотрю {props.lists[0]} +

+

+ {" "} + В планах {props.lists[1]} +

+

+ {" "} + Просмотрено {props.lists[2]} +

+

+ {" "} + Отложено {props.lists[3]} +

+

+ {" "} + Брошено {props.lists[4]} +

+
+

+ Просмотрено серий:{" "} + {props.watched_count} +

+

+ Время просмотра:{" "} + + ~{minutesToTime(props.watched_time, "daysHours")} + +

+
); }; diff --git a/app/components/RelatedSection/RelatedSection.tsx b/app/components/RelatedSection/RelatedSection.tsx index fa640b8..368793d 100644 --- a/app/components/RelatedSection/RelatedSection.tsx +++ b/app/components/RelatedSection/RelatedSection.tsx @@ -15,7 +15,7 @@ export const RelatedSection = (props: any) => {
{props.images.map((item, index) => { return ( -
+
{props.content.map((release) => { diff --git a/app/components/ReleaseInfo/ReleaseInfo.Info.tsx b/app/components/ReleaseInfo/ReleaseInfo.Info.tsx index 0ec3cd3..631ca88 100644 --- a/app/components/ReleaseInfo/ReleaseInfo.Info.tsx +++ b/app/components/ReleaseInfo/ReleaseInfo.Info.tsx @@ -59,7 +59,7 @@ export const ReleaseInfoInfo = (props: { {"/"} {props.episodes.total ? props.episodes.total + " эп. " : "? эп. "} {props.duration != 0 && - `по ${minutesToTime(props.duration)}`} + `по ${minutesToTime(props.duration, "daysHours")}`} diff --git a/app/components/ReleaseInfo/ReleaseInfo.SearchLink.tsx b/app/components/ReleaseInfo/ReleaseInfo.SearchLink.tsx index f7524a8..db19124 100644 --- a/app/components/ReleaseInfo/ReleaseInfo.SearchLink.tsx +++ b/app/components/ReleaseInfo/ReleaseInfo.SearchLink.tsx @@ -1,11 +1,19 @@ import Link from "next/link"; +// const searchBy = { +// title: 0, +// studio: 1, +// director: 2, +// author: 3, +// genre: 4 +// } + // TODO: сделать какую-нибудь анимацию на ссылке при наведении и фокусе -export const ReleaseInfoSearchLink = (props: { title: string, searchBy: string }) => { +export const ReleaseInfoSearchLink = (props: { title: string, searchBy: string | number | null }) => { return ( {props.title} diff --git a/app/components/ReleasePoster/PosterWithStuff.tsx b/app/components/ReleasePoster/PosterWithStuff.tsx index c4049ac..7ffbee2 100644 --- a/app/components/ReleasePoster/PosterWithStuff.tsx +++ b/app/components/ReleasePoster/PosterWithStuff.tsx @@ -83,7 +83,7 @@ export const PosterWithStuff = (props: { return ( {index > 0 && ", "} {genre} @@ -91,18 +91,18 @@ export const PosterWithStuff = (props: { ); })} {props.title_ru && ( -

+

{props.title_ru}

)} {props.title_original && ( -

+

{props.title_original}

)}
{settings.showDescription && props.description && ( -

+

{props.description}

)} diff --git a/app/components/ReleaseSection/ReleaseSection.tsx b/app/components/ReleaseSection/ReleaseSection.tsx index 95c4763..b826085 100644 --- a/app/components/ReleaseSection/ReleaseSection.tsx +++ b/app/components/ReleaseSection/ReleaseSection.tsx @@ -14,7 +14,7 @@ export const ReleaseSection = (props: {
)}
-
+
{props.content.map((release) => { return (
@@ -23,8 +23,8 @@ export const ReleaseSection = (props: { chipsSettings={{ enabled: true, lastWatchedHidden: - props.sectionTitle && - props.sectionTitle.toLowerCase() != "история", + (props.sectionTitle && + props.sectionTitle.toLowerCase() != "история") }} />
diff --git a/app/components/SettingsModal/SettingsModal.tsx b/app/components/SettingsModal/SettingsModal.tsx index 54a26a8..56d9291 100644 --- a/app/components/SettingsModal/SettingsModal.tsx +++ b/app/components/SettingsModal/SettingsModal.tsx @@ -35,11 +35,17 @@ const BookmarksCategory = { abandoned: "Заброшено", }; +const NavbarTitles = { + always: "Всегда", + links: "Только ссылки", + selected: "Только выбранные", + never: "Никогда", +}; + const FifthButton = { - favorites: "Избранное", - collections: "Коллекции", - history: "История", - discovery: "Обзор", + 3: "Избранное", + 4: "Коллекции", + 5: "История", }; export const SettingsModal = (props: { isOpen: boolean; setIsOpen: any }) => { @@ -50,8 +56,7 @@ export const SettingsModal = (props: { isOpen: boolean; setIsOpen: any }) => { const [isPlayerConfigured, setIsPlayerConfigured] = useState(false); useEffect(() => { - const NEXT_PUBLIC_PLAYER_PARSER_URL = - env("NEXT_PUBLIC_PLAYER_PARSER_URL") || null; + const NEXT_PUBLIC_PLAYER_PARSER_URL = env("NEXT_PUBLIC_PLAYER_PARSER_URL") || null; if (NEXT_PUBLIC_PLAYER_PARSER_URL) { setIsPlayerConfigured(true); } @@ -171,8 +176,35 @@ export const SettingsModal = (props: { isOpen: boolean; setIsOpen: any }) => {
: ""} +
+

+ Показывать название пункта в навигации +

+ + {Object.keys(NavbarTitles).map( + (key: "always" | "links" | "selected" | "never") => { + return ( + + preferenceStore.setFlags({ + showNavbarTitles: key, + }) + } + > + {NavbarTitles[key]} + + ); + } + )} + +
{userStore.isAuth ? -
+

Пятый пункт в навигации

@@ -198,7 +230,9 @@ export const SettingsModal = (props: { isOpen: boolean; setIsOpen: any }) => { - preferenceStore.setFlags({ showFifthButton: key }) + preferenceStore.setFlags({ + showFifthButton: Number(key) as 3 | 4 | 5, + }) } > {FifthButton[key]} @@ -228,7 +262,7 @@ export const SettingsModal = (props: { isOpen: boolean; setIsOpen: any }) => {

Сохранять историю просмотра

-

+

При отключении, история не будет сохранятся как локально, так и на аккаунте

@@ -251,7 +285,7 @@ export const SettingsModal = (props: { isOpen: boolean; setIsOpen: any }) => {

Новый плеер

-

+

Поддерживаемые источники: Kodik, Sibnet, Libria

diff --git a/app/components/UserSection/UserSection.tsx b/app/components/UserSection/UserSection.tsx index ece64fc..4dc7bfe 100644 --- a/app/components/UserSection/UserSection.tsx +++ b/app/components/UserSection/UserSection.tsx @@ -12,19 +12,20 @@ export const UserSection = (props: { sectionTitle?: string; content: any }) => {
)}
-
+
{props.content.map((user) => { return ( - - -
- -

{user.login}

-
+ + + +
+ {user.login} +
); })} + {props.content.length == 1 &&
}
diff --git a/app/discovery/collections/page.tsx b/app/discovery/collections/page.tsx deleted file mode 100644 index ff026f3..0000000 --- a/app/discovery/collections/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { DiscoverCollectionsPage } from "#/pages/DiscoverCollections"; - -export const metadata = { - title: "Обзор - Коллекции", - description: "", -}; - -export const dynamic = "force-static"; - -export default function Discover() { - return ; -} diff --git a/app/discovery/filter/page.tsx b/app/discovery/filter/page.tsx deleted file mode 100644 index a7144c4..0000000 --- a/app/discovery/filter/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { DiscoverFilterPage } from "#/pages/DiscoverFilter"; - -export const metadata = { - title: "Фильтр", - description: "Поиск по фильтру", -}; - -export const dynamic = "force-static"; - -export default function Discover() { - return ; -} diff --git a/app/discovery/page.tsx b/app/discovery/page.tsx deleted file mode 100644 index 448f517..0000000 --- a/app/discovery/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { DiscoverPage } from "#/pages/Discover"; - -export const metadata = { - title: "Обзор", - description: "Рекомендации и популярное", -}; - -export const dynamic = "force-static"; - -export default function Discover() { - return ; -} diff --git a/app/discovery/recommendations/page.tsx b/app/discovery/recommendations/page.tsx deleted file mode 100644 index 68ef980..0000000 --- a/app/discovery/recommendations/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { DiscoverRecommendationsPage } from "#/pages/DiscoverRecommendations"; - -export const metadata = { - title: "Обзор - Рекомендации", - description: "", -}; - -export const dynamic = "force-static"; - -export default function Discover() { - return ; -} diff --git a/app/discovery/watching/page.tsx b/app/discovery/watching/page.tsx deleted file mode 100644 index 799d3f0..0000000 --- a/app/discovery/watching/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { DiscoverWatchingPage } from "#/pages/DiscoverWatching"; - -export const metadata = { - title: "Обзор - Смотрят сейчас", - description: "Релизы которые сейчас смотрят", -}; - -export const dynamic = "force-static"; - -export default function Discover() { - return ; -} diff --git a/app/layout.tsx b/app/layout.tsx index 99240ee..0c0415f 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,7 +2,6 @@ import "./globals.css"; import { App } from "./App"; import { ThemeModeScript } from "flowbite-react"; import { PublicEnvScript } from 'next-runtime-env'; -import { ThemeInit } from "../.flowbite-react/init"; export const metadata = { metadataBase: new URL("https://anix.wah.su"), @@ -36,7 +35,6 @@ export default function RootLayout({ children }) { - {children} diff --git a/app/menu/page.tsx b/app/menu/page.tsx new file mode 100644 index 0000000..61305cc --- /dev/null +++ b/app/menu/page.tsx @@ -0,0 +1,11 @@ +export const metadata = { + title: "Меню", +}; + +import { MenuPage } from "#/pages/MobileMenuPage"; + +export const dynamic = "force-static"; + +export default function Index() { + return ; +} diff --git a/app/pages/BookmarksCategory.tsx b/app/pages/BookmarksCategory.tsx index 3590e50..b53b3fa 100644 --- a/app/pages/BookmarksCategory.tsx +++ b/app/pages/BookmarksCategory.tsx @@ -82,7 +82,7 @@ export function BookmarksCategoryPage(props: any) {
); - } + }; if (error) { return ( @@ -105,9 +105,7 @@ export function BookmarksCategoryPage(props: any) { className="flex-1 max-w-full mx-4" onSubmit={(e) => { e.preventDefault(); - router.push( - `/search?query=${searchVal}¶ms={"where"%3A"list"%2C"searchBy"%3A"${props.slug}"}` - ); + router.push(`/search?q=${searchVal}&where=list&list=${props.slug}`); }} >
- {content && content.length > 0 ? + {content && content.length > 0 ? ( - : isLoading ? + ) : isLoading ? (
- :
+ ) : ( +

В избранном пока ничего нет...

- } + )} {data && data[data.length - 1].current_page < data[data.length - 1].total_page_count && ( diff --git a/app/pages/History.tsx b/app/pages/History.tsx index 7b4c495..73c9f10 100644 --- a/app/pages/History.tsx +++ b/app/pages/History.tsx @@ -10,6 +10,7 @@ import { Button } from "flowbite-react"; import { useRouter } from "next/navigation"; import { useSWRfetcher } from "#/api/utils"; + export function HistoryPage() { const token = useUserStore((state) => state.token); const authState = useUserStore((state) => state.state); @@ -61,9 +62,7 @@ export function HistoryPage() { className="flex-1 max-w-full mx-4 mb-4" onSubmit={(e) => { e.preventDefault(); - router.push( - `/search?query=${searchVal}¶ms={"where"%3A"history"%2C"searchBy"%3A"none"}` - ); + router.push(`/search?q=${searchVal}&where=history`); }} >
- {content && content.length > 0 ? + {content && content.length > 0 ? ( <> {data && data[0].total_count != content.length && ( @@ -123,15 +122,16 @@ export function HistoryPage() { )} - : isLoading ? + ) : isLoading ? (
- :
+ ) : ( +

В истории пока ничего нет...

- } + )} ); } diff --git a/app/pages/Index.tsx b/app/pages/Index.tsx index ef6eef8..c40c057 100644 --- a/app/pages/Index.tsx +++ b/app/pages/Index.tsx @@ -3,22 +3,15 @@ import { ReleaseCourusel } from "#/components/ReleaseCourusel/ReleaseCourusel"; import { Spinner } from "#/components/Spinner/Spinner"; import { useUserStore } from "#/store/auth"; import { useState, useEffect } from "react"; -import { FetchFilter } from "#/api/utils"; +import { _FetchHomePageReleases } from "#/api/utils"; import { usePreferencesStore } from "#/store/preferences"; import { useRouter } from "next/navigation"; -import { - ListAnnounce, - ListFilms, - ListFinished, - ListLast, - ListOngoing, -} from "./IndexFilters"; export function IndexPage() { const token = useUserStore((state) => state.token); const preferenceStore = usePreferencesStore(); - const router = useRouter(); + const router = useRouter() const [isLoading, setIsLoading] = useState(true); const [lastReleasesData, setLastReleasesData] = useState(null); const [ongoingReleasesData, setOngoingReleasesData] = useState(null); @@ -28,9 +21,7 @@ export function IndexPage() { useEffect(() => { if (preferenceStore.params.skipToCategory.enabled) { - router.push( - `/home/${preferenceStore.params.skipToCategory.homeCategory}` - ); + router.push(`/home/${preferenceStore.params.skipToCategory.homeCategory}`); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -44,19 +35,11 @@ export function IndexPage() { setAnnounceReleasesData(null); setFilmsReleasesData(null); - const [lastReleases] = await FetchFilter(ListLast.filter, 0, token); - const [ongoingReleases] = await FetchFilter(ListOngoing.filter, 0, token); - const [announceReleases] = await FetchFilter( - ListAnnounce.filter, - 0, - token - ); - const [finishedReleases] = await FetchFilter( - ListFinished.filter, - 0, - token - ); - const [filmsReleases] = await FetchFilter(ListFilms.filter, 0, token); + const lastReleases = await _FetchHomePageReleases("last", token); + const ongoingReleases = await _FetchHomePageReleases("ongoing", token); + const finishedReleases = await _FetchHomePageReleases("finished", token); + const announceReleases = await _FetchHomePageReleases("announce", token); + const filmsReleases = await _FetchHomePageReleases("films", token); setLastReleasesData(lastReleases); setOngoingReleasesData(ongoingReleases); @@ -73,12 +56,16 @@ export function IndexPage() { return ( <> - {lastReleasesData && ( + {lastReleasesData ? ( + ) : ( +
+ +
)} {finishedReleasesData && ( )} - {isLoading && ( -
- -
- )} + {!isLoading && + !lastReleasesData && + !finishedReleasesData && + !ongoingReleasesData && + !announceReleasesData && ( +
+

Ошибка загрузки контента...

+
+ )} ); } diff --git a/app/pages/IndexCategory.tsx b/app/pages/IndexCategory.tsx index bf10bed..f3ba11d 100644 --- a/app/pages/IndexCategory.tsx +++ b/app/pages/IndexCategory.tsx @@ -4,10 +4,9 @@ import { Spinner } from "#/components/Spinner/Spinner"; import { useState, useEffect } from "react"; import { useScrollPosition } from "#/hooks/useScrollPosition"; import { useUserStore } from "../store/auth"; -import { FetchFilter } from "#/api/utils"; +import { _FetchHomePageReleases } from "#/api/utils"; import { Button, ButtonGroup } from "flowbite-react"; import { useRouter } from "next/navigation"; -import { slugToFilter } from "./IndexFilters"; export function IndexCategoryPage(props) { const token = useUserStore((state) => state.token); @@ -21,7 +20,7 @@ export function IndexCategoryPage(props) { setIsLoading(true); setContent(null); - const [ data ] = await FetchFilter(slugToFilter[props.slug].filter, page, token); + const data: any = await _FetchHomePageReleases(props.slug, token, page); setContent(data.content); setIsLoading(false); @@ -33,7 +32,7 @@ export function IndexCategoryPage(props) { useEffect(() => { async function _loadNextReleasesPage() { - const [ data ] = await FetchFilter(slugToFilter[props.slug].filter, page, token); + const data: any = await _FetchHomePageReleases(props.slug, token, page); const newContent = [...content, ...data.content]; setContent(newContent); } diff --git a/app/pages/IndexFilters.ts b/app/pages/IndexFilters.ts deleted file mode 100644 index 0432d99..0000000 --- a/app/pages/IndexFilters.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { FilterDefault } from "#/api/utils"; - -export const ListLast = { - name: "Последнее", - filter: FilterDefault, -}; - -export const ListOngoing = { - name: "Онгоинги", - filter: { ...FilterDefault, status_id: 2 }, -}; - -export const ListAnnounce = { - name: "Анонсы", - filter: { ...FilterDefault, status_id: 3 }, -}; - -export const ListFinished = { - name: "Завершённые", - filter: { ...FilterDefault, status_id: 1 }, -}; - -export const ListFilms = { - name: "Фильмы", - filter: { ...FilterDefault, category_id: 2 }, -}; - -export const slugToFilter = { - last: ListLast, - ongoing: ListOngoing, - announce: ListAnnounce, - finished: ListFinished, - films: ListFilms, -} \ No newline at end of file diff --git a/app/pages/MobileMenuPage.tsx b/app/pages/MobileMenuPage.tsx new file mode 100644 index 0000000..f1f73b8 --- /dev/null +++ b/app/pages/MobileMenuPage.tsx @@ -0,0 +1,130 @@ +"use client"; +import { Card } from "flowbite-react"; +import { useUserStore } from "#/store/auth"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { SettingsModal } from "#/components/SettingsModal/SettingsModal"; +import { useEffect, useState } from "react"; +import Image from "next/image"; +import { usePreferencesStore } from "#/store/preferences"; + +export const MenuPage = () => { + const userStore = useUserStore(); + const preferenceStore = usePreferencesStore(); + const router = useRouter(); + const [isSettingModalOpen, setIsSettingModalOpen] = useState(false); + + useEffect(() => { + if (!userStore.user) { + router.push("/"); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [userStore.user]); + + return ( + <> + {userStore.user && ( +
+
+ + +
+ +
+

+ {userStore.user.login} +

+

+ {userStore.user.status} +

+
+
+
+ +
+ + +
+
+ {preferenceStore.flags.showFifthButton != 3 ? + + +
+ +

Избранное

+
+
+ + : ""} + {preferenceStore.flags.showFifthButton != 4 ? + + +
+ +

Коллекции

+
+
+ + : ""} + {preferenceStore.flags.showFifthButton != 5 ? + + +
+ +

История

+
+
+ + : ""} + +
+ )} + + ); +}; diff --git a/app/pages/Profile.tsx b/app/pages/Profile.tsx index 6eab266..fdd44b4 100644 --- a/app/pages/Profile.tsx +++ b/app/pages/Profile.tsx @@ -164,9 +164,6 @@ export const ProfilePage = (props: any) => { watched_count={user.watched_episode_count} watched_time={user.watched_time} profile_id={user.id} - preferred_genres={user.preferred_genres || []} - preferred_audiences={user.preferred_audiences || []} - preferred_themes={user.preferred_themes || []} />
diff --git a/app/pages/Search.tsx b/app/pages/Search.tsx index 0f58262..c5ee065 100644 --- a/app/pages/Search.tsx +++ b/app/pages/Search.tsx @@ -243,7 +243,7 @@ export function SearchPage() { return [url, JSON.stringify({ query, searchBy })]; }; - const { data, error, isLoading, size, setSize } = useSWRInfinite( + const { data, error, isLoading, size, setSize, mutate } = useSWRInfinite( getKey, ([url, payload]) => postFetcher(url, payload), { initialSize: 2 } @@ -279,7 +279,7 @@ export function SearchPage() { return (
diff --git a/app/store/preferences.ts b/app/store/preferences.ts index 056038b..1225c2d 100644 --- a/app/store/preferences.ts +++ b/app/store/preferences.ts @@ -9,7 +9,8 @@ interface preferencesState { // saveSearchHistory: boolean; saveWatchHistory?: boolean; showChangelog?: boolean; - showFifthButton?: null | string; + showNavbarTitles?: "always" | "links" | "selected" | "never"; + showFifthButton?: null | 3 | 4 | 5; }; params: { isFirstLaunch?: boolean; @@ -38,9 +39,11 @@ export const usePreferencesStore = create()( (set, get) => ({ _hasHydrated: false, flags: { + // saveSearchHistory: true, saveWatchHistory: true, showChangelog: true, - showFifthButton: "discovery", + showNavbarTitles: "always", + showFifthButton: null, }, params: { isFirstLaunch: true, @@ -77,7 +80,6 @@ export const usePreferencesStore = create()( persistedState as preferencesState ); }, - version: 2, - }, + } ) ); diff --git a/next.config.mjs b/next.config.js similarity index 93% rename from next.config.mjs rename to next.config.js index 08b5070..24aa345 100644 --- a/next.config.mjs +++ b/next.config.js @@ -1,5 +1,4 @@ -import withFlowbiteReact from "flowbite-react/plugin/nextjs"; - +const withFlowbiteReact = require("flowbite-react/plugin/nextjs"); /** @type {import('next').NextConfig} */ const NextConfig = { output: "standalone", @@ -81,4 +80,6 @@ const NextConfig = { }, }; -export default withFlowbiteReact(NextConfig); +const config = withFlowbiteReact(NextConfig); + +module.exports = config; diff --git a/package-lock.json b/package-lock.json index cfb8bd5..6309d00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,11 +7,12 @@ "": { "name": "new", "version": "0.1.0", + "hasInstallScript": true, "dependencies": { "apexcharts": "^3.52.0", "deepmerge-ts": "^7.1.0", "flowbite": "^2.4.1", - "flowbite-react": "^0.12.7", + "flowbite-react": "^0.11.7", "hls-video-element": "^1.5.0", "markdown-to-jsx": "^7.4.7", "media-chrome": "^4.9.0", @@ -3347,9 +3348,9 @@ } }, "node_modules/flowbite-react": { - "version": "0.12.7", - "resolved": "https://registry.npmjs.org/flowbite-react/-/flowbite-react-0.12.7.tgz", - "integrity": "sha512-d8GR7mnCfdIl4n5RXxz4dKin6DIEA7Ax9mXDpJhz9gwxaPKUklKJZKtQ+KkdmFNrB65Zy76Pam01yr3LcxlseA==", + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/flowbite-react/-/flowbite-react-0.11.7.tgz", + "integrity": "sha512-Z8m+ycHEsXPacSAi8P4yYDeff7LvcHNwbGAnL/+Fpiv+6ZWDEAGY/YPKhUofZsZa837JTYrbcbmgjqQ1bpt51g==", "license": "MIT", "dependencies": { "@floating-ui/core": "1.6.9", diff --git a/package.json b/package.json index 25d6ab0..10c8582 100644 --- a/package.json +++ b/package.json @@ -7,13 +7,14 @@ "dev-with-services": "node ./run-all.dev.js", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "postinstall": "flowbite-react patch" }, "dependencies": { "apexcharts": "^3.52.0", "deepmerge-ts": "^7.1.0", "flowbite": "^2.4.1", - "flowbite-react": "^0.12.7", + "flowbite-react": "^0.11.7", "hls-video-element": "^1.5.0", "markdown-to-jsx": "^7.4.7", "media-chrome": "^4.9.0", diff --git a/public/changelog/3.9.0.md b/public/changelog/3.9.0.md deleted file mode 100644 index c782610..0000000 --- a/public/changelog/3.9.0.md +++ /dev/null @@ -1,21 +0,0 @@ -# 3.9.0 - -## Добавлено - -- Статистика тематика, жанры и аудитория в статистике профиля -- Страница "Обзор" - -## Изменено - -- Секции карточек релизов теперь в 2 колонки на телефонах -- Вид карточек в поиске пользователей -- По стандарту пятой кнопкой в мобильном навбаре стоит пункт "обзор" - -## Исправлено - -- Неправильное время просмотра в статистике профиле в некоторых случаях -- Ссылки на переход в поиск с страницы релиза, закладок, избранных, истории, коллекциях теперь работают для нового поиска - -## Удалено - -- Настройки показа названий страниц в навигации diff --git a/tailwind.config.js b/tailwind.config.js index 83bda1a..d5a11ca 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -11,7 +11,7 @@ module.exports = { "./pages/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", "./app/**/*.{js,ts,jsx,tsx,mdx}", - ".flowbite-react/class-list.json" + ".flowbite-react\\class-list.json" ], plugins: [ addIconSelectors(["mdi", "material-symbols", "twemoji", "fa6-brands", "solar"]), diff --git a/tsconfig.json b/tsconfig.json index f7fcd08..b0d0bcc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,7 +31,7 @@ ".next/types/**/*.ts", "**/*.ts", "**/*.tsx", - "next.config.mjs" + "next.config.js" ], "exclude": ["node_modules", "player-parser", "api-prox"] }