mirror of
https://github.com/Radiquum/AniX.git
synced 2025-09-07 15:03:53 +05:00
Compare commits
9 commits
762c2f324a
...
84698dafca
Author | SHA1 | Date | |
---|---|---|---|
84698dafca | |||
bdbb8cc548 | |||
ff2dbdfac1 | |||
4a45b7af56 | |||
de6dcabbc7 | |||
3f85d0e340 | |||
5bc65da8e3 | |||
b9bf9e9bd8 | |||
e363838e98 |
10 changed files with 331 additions and 42 deletions
|
@ -1,4 +1,4 @@
|
||||||
export const CURRENT_APP_VERSION = "3.5.0";
|
export const CURRENT_APP_VERSION = "3.6.0";
|
||||||
|
|
||||||
export const API_URL = "https://api.anixart.tv";
|
export const API_URL = "https://api.anixart.tv";
|
||||||
export const API_PREFIX = "/api/proxy";
|
export const API_PREFIX = "/api/proxy";
|
||||||
|
|
90
app/components/ContinueWatching/ContinueWatching.tsx
Normal file
90
app/components/ContinueWatching/ContinueWatching.tsx
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Card } from "flowbite-react";
|
||||||
|
import { ReleaseLinkList } from "#/components/ReleaseLink/ReleaseLinkList";
|
||||||
|
import { useUserStore } from "#/store/auth";
|
||||||
|
import { ENDPOINTS } from "#/api/config";
|
||||||
|
import { BookmarksList, useSWRfetcher } from "#/api/utils";
|
||||||
|
import useSWR from "swr";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export const ContinueWatching = () => {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
function useFetchReleases(listName: string) {
|
||||||
|
let url: string;
|
||||||
|
if (userStore.token) {
|
||||||
|
url = `${ENDPOINTS.user.bookmark}/all/${BookmarksList[listName]}/0?sort=1&token=${userStore.token}`;
|
||||||
|
}
|
||||||
|
const { data, isLoading, error } = useSWR(url, useSWRfetcher);
|
||||||
|
return [data, isLoading, error];
|
||||||
|
}
|
||||||
|
|
||||||
|
const [watchingData, watchingLoading, watchingError] =
|
||||||
|
useFetchReleases("watching");
|
||||||
|
const [plannedData, plannedLoading, plannedError] =
|
||||||
|
useFetchReleases("planned");
|
||||||
|
const [delayedData, delayedLoading, delayedError] =
|
||||||
|
useFetchReleases("delayed");
|
||||||
|
|
||||||
|
const [releaseData, setReleaseData] = useState<any[]>([]);
|
||||||
|
|
||||||
|
const firstN = (arr, n = 1) => arr.slice(0, n);
|
||||||
|
function _randomize(array: any[], limit: number) {
|
||||||
|
const toRand = array.slice();
|
||||||
|
let currentIndex = toRand.length;
|
||||||
|
while (currentIndex != 0) {
|
||||||
|
let randomIndex = Math.floor(Math.random() * currentIndex);
|
||||||
|
currentIndex--;
|
||||||
|
[toRand[currentIndex], toRand[randomIndex]] = [
|
||||||
|
toRand[randomIndex],
|
||||||
|
toRand[currentIndex],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return firstN(toRand, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!watchingLoading && !plannedLoading && !delayedLoading) {
|
||||||
|
const data = [
|
||||||
|
...(watchingData.content || []),
|
||||||
|
...(plannedData.content || []),
|
||||||
|
...(delayedData.content || []),
|
||||||
|
];
|
||||||
|
console.log("loaded data:", data);
|
||||||
|
const randomizedData = _randomize(data, 3);
|
||||||
|
setReleaseData(randomizedData);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [watchingLoading, plannedLoading, delayedLoading]);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!userStore.isAuth ||
|
||||||
|
watchingLoading ||
|
||||||
|
plannedLoading ||
|
||||||
|
delayedLoading ||
|
||||||
|
releaseData.length == 0
|
||||||
|
)
|
||||||
|
return <></>;
|
||||||
|
|
||||||
|
console.log("randomized data:", releaseData);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<div className="flex justify-between py-2 border-b-2 border-black dark:border-white">
|
||||||
|
<h1>Продолжить просмотр</h1>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-4 mt-2">
|
||||||
|
{releaseData.map((release: any) => {
|
||||||
|
return (
|
||||||
|
<ReleaseLinkList
|
||||||
|
key={release.id}
|
||||||
|
{...release}
|
||||||
|
settings={{ showDescription: false }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
|
@ -17,7 +17,7 @@ export const ProfileActivityComment = (props: {
|
||||||
key={`comment-${comment.id}`}
|
key={`comment-${comment.id}`}
|
||||||
>
|
>
|
||||||
<footer className="flex items-center justify-between mb-2">
|
<footer className="flex items-center justify-between mb-2">
|
||||||
<div className="flex flex-col items-start gap-1 sm:items-center sm:flex-row">
|
<div className="flex items-center gap-1">
|
||||||
<Link
|
<Link
|
||||||
href={`/profile/${comment.profile.id}`}
|
href={`/profile/${comment.profile.id}`}
|
||||||
className="inline-flex items-center mr-3 text-sm font-semibold text-gray-900 dark:text-white hover:underline"
|
className="inline-flex items-center mr-3 text-sm font-semibold text-gray-900 dark:text-white hover:underline"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Card, Carousel } from "flowbite-react";
|
import { Card } from "flowbite-react";
|
||||||
import { ReleaseLink } from "#/components/ReleaseLink/ReleaseLinkUpdate";
|
import { ReleaseLinkList } from "#/components/ReleaseLink/ReleaseLinkList";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
export const ReleaseInfoRelated = (props: {
|
export const ReleaseInfoRelated = (props: {
|
||||||
|
@ -22,25 +22,23 @@ export const ReleaseInfoRelated = (props: {
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center mt-2">
|
<div className="flex flex-col gap-4 mt-2">
|
||||||
<Carousel pauseOnHover={true}>
|
{props.related_releases
|
||||||
{props.related_releases
|
.filter((release: any) => {
|
||||||
.filter((release: any) => {
|
if (release.id == props.release_id) {
|
||||||
if (release.id == props.release_id) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
return true;
|
||||||
return true;
|
})
|
||||||
})
|
.map((release: any) => {
|
||||||
.map((release: any) => {
|
return (
|
||||||
return (
|
<ReleaseLinkList
|
||||||
<ReleaseLink
|
key={release.id}
|
||||||
key={release.id}
|
{...release}
|
||||||
{...release}
|
settings={{ showGenres: false, showDescription: false }}
|
||||||
settings={{ showGenres: false, showDescription: false }}
|
/>
|
||||||
/>
|
);
|
||||||
);
|
})}
|
||||||
})}
|
|
||||||
</Carousel>
|
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,21 +1,63 @@
|
||||||
import { Card, Carousel } from "flowbite-react";
|
import { Card } from "flowbite-react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
|
import "swiper/css";
|
||||||
|
import "swiper/css/navigation";
|
||||||
|
import "swiper/css/pagination";
|
||||||
|
import "swiper/css/autoplay";
|
||||||
|
import { Navigation, Pagination, Autoplay } from "swiper/modules";
|
||||||
|
|
||||||
export const ReleaseInfoScreenshots = (props: { images: string[] }) => {
|
export const ReleaseInfoScreenshots = (props: { images: string[] }) => {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<Carousel className="aspect-[16/10]">
|
<Swiper
|
||||||
{props.images.map((image: string, index: number) => (
|
modules={[Navigation, Pagination, Autoplay]}
|
||||||
<Image
|
spaceBetween={8}
|
||||||
key={index}
|
slidesPerView={2}
|
||||||
className="object-cover"
|
direction={"horizontal"}
|
||||||
src={image}
|
allowTouchMove={true}
|
||||||
width={400}
|
autoplay={true}
|
||||||
height={300}
|
pagination={true}
|
||||||
alt=""
|
breakpoints={{
|
||||||
/>
|
1024: {
|
||||||
))}
|
slidesPerView: 1,
|
||||||
</Carousel>
|
},
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
height: "100%",
|
||||||
|
minHeight: 0,
|
||||||
|
maxHeight: "100%",
|
||||||
|
width: "100%",
|
||||||
|
minWidth: 0,
|
||||||
|
maxWidth: "100%",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.images.map((image: string, index: number) => {
|
||||||
|
return (
|
||||||
|
<SwiperSlide
|
||||||
|
key={`release-screenshot-${index}`}
|
||||||
|
style={{
|
||||||
|
width: "fit-content",
|
||||||
|
flexShrink: 0,
|
||||||
|
display: "block",
|
||||||
|
height: "100%",
|
||||||
|
maxHeight: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
key={index}
|
||||||
|
className="object-cover"
|
||||||
|
src={image}
|
||||||
|
width={400}
|
||||||
|
height={225}
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</SwiperSlide>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Swiper>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
118
app/components/ReleaseLink/ReleaseLinkList.tsx
Normal file
118
app/components/ReleaseLink/ReleaseLinkList.tsx
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
import Link from "next/link";
|
||||||
|
import { Poster } from "../ReleasePoster/Poster";
|
||||||
|
import { ReleaseChips } from "../ReleasePoster/Chips";
|
||||||
|
|
||||||
|
const profile_lists = {
|
||||||
|
// 0: "Не смотрю",
|
||||||
|
1: { name: "Смотрю", bg_color: "bg-green-500" },
|
||||||
|
2: { name: "В планах", bg_color: "bg-purple-500" },
|
||||||
|
3: { name: "Просмотрено", bg_color: "bg-blue-500" },
|
||||||
|
4: { name: "Отложено", bg_color: "bg-yellow-500" },
|
||||||
|
5: { name: "Брошено", bg_color: "bg-red-500" },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ReleaseLinkList = (props: {
|
||||||
|
image: string;
|
||||||
|
title_ru: string;
|
||||||
|
title_original: string;
|
||||||
|
description?: string;
|
||||||
|
genres?: string;
|
||||||
|
grade?: number;
|
||||||
|
id: number;
|
||||||
|
settings?: {
|
||||||
|
showGenres?: boolean;
|
||||||
|
showDescription?: boolean;
|
||||||
|
showOrigTitle?: boolean;
|
||||||
|
};
|
||||||
|
chipsSettings?: {
|
||||||
|
enabled: boolean;
|
||||||
|
gradeHidden?: boolean;
|
||||||
|
statusHidden?: boolean;
|
||||||
|
categoryHidden?: boolean;
|
||||||
|
episodesHidden?: boolean;
|
||||||
|
listHidden?: boolean;
|
||||||
|
favHidden?: boolean;
|
||||||
|
lastWatchedHidden?: boolean;
|
||||||
|
};
|
||||||
|
profile_list_status?: number;
|
||||||
|
status?: {
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
category?: {
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
status_id?: number;
|
||||||
|
episodes_released?: string;
|
||||||
|
episodes_total?: string;
|
||||||
|
is_favorite?: boolean;
|
||||||
|
}) => {
|
||||||
|
const genres = [];
|
||||||
|
const settings = {
|
||||||
|
showGenres: true,
|
||||||
|
showDescription: true,
|
||||||
|
showOrigTitle: true,
|
||||||
|
...props.settings,
|
||||||
|
};
|
||||||
|
const chipsSettings = props.chipsSettings || {};
|
||||||
|
|
||||||
|
const grade = props.grade ? Number(props.grade.toFixed(1)) : null;
|
||||||
|
const profile_list_status = props.profile_list_status || null;
|
||||||
|
let user_list = null;
|
||||||
|
if (profile_list_status != null || profile_list_status != 0) {
|
||||||
|
user_list = profile_lists[profile_list_status];
|
||||||
|
}
|
||||||
|
if (props.genres) {
|
||||||
|
const genres_array = props.genres.split(",");
|
||||||
|
genres_array.forEach((genre) => {
|
||||||
|
genres.push(genre.trim());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link href={`/release/${props.id}`}>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<div className="flex-shrink-0 w-32">
|
||||||
|
<Poster image={props.image} className="h-auto" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
<ReleaseChips
|
||||||
|
{...props}
|
||||||
|
user_list={user_list}
|
||||||
|
grade={grade}
|
||||||
|
settings={{ lastWatchedHidden: false }}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
{settings.showGenres &&
|
||||||
|
genres.length > 0 &&
|
||||||
|
genres.map((genre: string, index: number) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
key={`release_${props.id}_genre_${genre}_${index}`}
|
||||||
|
className="text-sm font-light leading-none dark:text-white"
|
||||||
|
>
|
||||||
|
{index > 0 && ", "}
|
||||||
|
{genre}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{props.title_ru && (
|
||||||
|
<p className="text-lg font-bold line-clamp-2 dark:text-white">
|
||||||
|
{props.title_ru}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
{settings.showOrigTitle && props.title_original && (
|
||||||
|
<p className="text-sm text-gray-600 line-clamp-2 dark:text-gray-300">
|
||||||
|
{props.title_original}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
{settings.showDescription && props.description && (
|
||||||
|
<p className="mt-2 text-sm font-light leading-none text-white lg:text-base xl:text-lg line-clamp-4">
|
||||||
|
{props.description}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
|
@ -18,6 +18,7 @@ import { CommentsMain } from "#/components/Comments/Comments.Main";
|
||||||
import { InfoLists } from "#/components/InfoLists/InfoLists";
|
import { InfoLists } from "#/components/InfoLists/InfoLists";
|
||||||
import { ENDPOINTS } from "#/api/config";
|
import { ENDPOINTS } from "#/api/config";
|
||||||
import { usePreferencesStore } from "#/store/preferences";
|
import { usePreferencesStore } from "#/store/preferences";
|
||||||
|
import { ContinueWatching } from "#/components/ContinueWatching/ContinueWatching";
|
||||||
|
|
||||||
export const ReleasePage = (props: any) => {
|
export const ReleasePage = (props: any) => {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
@ -71,7 +72,7 @@ export const ReleasePage = (props: any) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2 pb-8">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-[70%_30%] gap-2 grid-flow-row-dense">
|
<div className="grid grid-cols-1 lg:grid-cols-[70%_30%] gap-2 grid-flow-row-dense">
|
||||||
<ReleaseInfoBasics
|
<ReleaseInfoBasics
|
||||||
image={data.release.image}
|
image={data.release.image}
|
||||||
|
@ -122,11 +123,13 @@ export const ReleasePage = (props: any) => {
|
||||||
: <ReleasePlayer id={props.id} />}
|
: <ReleasePlayer id={props.id} />}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<CommentsMain
|
<div className="hidden lg:block">
|
||||||
release_id={props.id}
|
<CommentsMain
|
||||||
token={userStore.token}
|
release_id={props.id}
|
||||||
comments={data.release.comments}
|
token={userStore.token}
|
||||||
/>
|
comments={data.release.comments}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
{data.release.status &&
|
{data.release.status &&
|
||||||
|
@ -165,6 +168,14 @@ export const ReleasePage = (props: any) => {
|
||||||
related_releases={data.release.related_releases}
|
related_releases={data.release.related_releases}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{userStore.token && <ContinueWatching />}
|
||||||
|
<div className="block lg:hidden">
|
||||||
|
<CommentsMain
|
||||||
|
release_id={props.id}
|
||||||
|
token={userStore.token}
|
||||||
|
comments={data.release.comments}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
11
package-lock.json
generated
11
package-lock.json
generated
|
@ -39,6 +39,7 @@
|
||||||
"copy-webpack-plugin": "^12.0.2",
|
"copy-webpack-plugin": "^12.0.2",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.5",
|
"eslint-config-next": "14.2.5",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
}
|
}
|
||||||
|
@ -2984,6 +2985,16 @@
|
||||||
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
|
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eslint-plugin-react-refresh": {
|
||||||
|
"version": "0.4.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.19.tgz",
|
||||||
|
"integrity": "sha512-eyy8pcr/YxSYjBoqIFSrlbn9i/xvxUFa8CjzAYo9cFjgGXqq1hyjihcpZvxRLalpaWmueWR81xn7vuKmAFijDQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": ">=8.40"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eslint-plugin-react/node_modules/doctrine": {
|
"node_modules/eslint-plugin-react/node_modules/doctrine": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
"copy-webpack-plugin": "^12.0.2",
|
"copy-webpack-plugin": "^12.0.2",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.5",
|
"eslint-config-next": "14.2.5",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.4.1"
|
"tailwindcss": "^3.4.1"
|
||||||
}
|
}
|
||||||
|
|
18
public/changelog/3.6.0.md
Normal file
18
public/changelog/3.6.0.md
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# 3.6.0
|
||||||
|
|
||||||
|
## Добавлено
|
||||||
|
|
||||||
|
- Добавлена возможность смотреть заблокированных пользователей (в меню редактирования профиля)
|
||||||
|
- Добавлена возможность смотреть друзей пользователя
|
||||||
|
- Добавлена возможность смотреть, принимать и скрывать заявки в друзья
|
||||||
|
- Добавлен просмотр популярных комментариев пользователя
|
||||||
|
- Добавлен блок "Продолжить просмотр" на странице релиза если был произведён вход в аккаунт (3 рандомных релиза из списков сморю, в планах и отложено)
|
||||||
|
|
||||||
|
## Изменено
|
||||||
|
|
||||||
|
- Стиль некоторых элементов был изменён в связи с обновление библиотеки компонентов
|
||||||
|
- Блок скриншотов был перенесён на другую библиотеку
|
||||||
|
- Изменён вид блока связанных релизов на странице релиза с карусели карточек на список
|
||||||
|
- Изменён блок активности на странице профиля
|
||||||
|
- Изменены виды блоков "Оценки" и "Недавно просмотренные" на странице профиля с карусели карточек на список
|
||||||
|
- Изменён вид блока профиля (соц. сети и роли)
|
Loading…
Add table
Add a link
Reference in a new issue