Compare commits

...

9 commits

10 changed files with 331 additions and 42 deletions

View file

@ -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_PREFIX = "/api/proxy";

View 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>
);
};

View file

@ -17,7 +17,7 @@ export const ProfileActivityComment = (props: {
key={`comment-${comment.id}`}
>
<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
href={`/profile/${comment.profile.id}`}
className="inline-flex items-center mr-3 text-sm font-semibold text-gray-900 dark:text-white hover:underline"

View file

@ -1,7 +1,7 @@
"use client";
import { Card, Carousel } from "flowbite-react";
import { ReleaseLink } from "#/components/ReleaseLink/ReleaseLinkUpdate";
import { Card } from "flowbite-react";
import { ReleaseLinkList } from "#/components/ReleaseLink/ReleaseLinkList";
import Link from "next/link";
export const ReleaseInfoRelated = (props: {
@ -22,25 +22,23 @@ export const ReleaseInfoRelated = (props: {
</Link>
)}
</div>
<div className="flex justify-center mt-2">
<Carousel pauseOnHover={true}>
{props.related_releases
.filter((release: any) => {
if (release.id == props.release_id) {
return false;
}
return true;
})
.map((release: any) => {
return (
<ReleaseLink
key={release.id}
{...release}
settings={{ showGenres: false, showDescription: false }}
/>
);
})}
</Carousel>
<div className="flex flex-col gap-4 mt-2">
{props.related_releases
.filter((release: any) => {
if (release.id == props.release_id) {
return false;
}
return true;
})
.map((release: any) => {
return (
<ReleaseLinkList
key={release.id}
{...release}
settings={{ showGenres: false, showDescription: false }}
/>
);
})}
</div>
</Card>
);

View file

@ -1,21 +1,63 @@
import { Card, Carousel } from "flowbite-react";
import { Card } from "flowbite-react";
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[] }) => {
return (
<Card>
<Carousel className="aspect-[16/10]">
{props.images.map((image: string, index: number) => (
<Image
key={index}
className="object-cover"
src={image}
width={400}
height={300}
alt=""
/>
))}
</Carousel>
<Swiper
modules={[Navigation, Pagination, Autoplay]}
spaceBetween={8}
slidesPerView={2}
direction={"horizontal"}
allowTouchMove={true}
autoplay={true}
pagination={true}
breakpoints={{
1024: {
slidesPerView: 1,
},
}}
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>
);
};

View 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>
);
};

View file

@ -18,6 +18,7 @@ import { CommentsMain } from "#/components/Comments/Comments.Main";
import { InfoLists } from "#/components/InfoLists/InfoLists";
import { ENDPOINTS } from "#/api/config";
import { usePreferencesStore } from "#/store/preferences";
import { ContinueWatching } from "#/components/ContinueWatching/ContinueWatching";
export const ReleasePage = (props: any) => {
const userStore = useUserStore();
@ -71,7 +72,7 @@ export const ReleasePage = (props: any) => {
}
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">
<ReleaseInfoBasics
image={data.release.image}
@ -122,11 +123,13 @@ export const ReleasePage = (props: any) => {
: <ReleasePlayer id={props.id} />}
</>
)}
<CommentsMain
release_id={props.id}
token={userStore.token}
comments={data.release.comments}
/>
<div className="hidden lg:block">
<CommentsMain
release_id={props.id}
token={userStore.token}
comments={data.release.comments}
/>
</div>
</div>
<div className="flex flex-col gap-2">
{data.release.status &&
@ -165,6 +168,14 @@ export const ReleasePage = (props: any) => {
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>

11
package-lock.json generated
View file

@ -39,6 +39,7 @@
"copy-webpack-plugin": "^12.0.2",
"eslint": "^8",
"eslint-config-next": "14.2.5",
"eslint-plugin-react-refresh": "^0.4.19",
"postcss": "^8",
"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"
}
},
"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": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",

View file

@ -40,6 +40,7 @@
"copy-webpack-plugin": "^12.0.2",
"eslint": "^8",
"eslint-config-next": "14.2.5",
"eslint-plugin-react-refresh": "^0.4.19",
"postcss": "^8",
"tailwindcss": "^3.4.1"
}

18
public/changelog/3.6.0.md Normal file
View file

@ -0,0 +1,18 @@
# 3.6.0
## Добавлено
- Добавлена возможность смотреть заблокированных пользователей (в меню редактирования профиля)
- Добавлена возможность смотреть друзей пользователя
- Добавлена возможность смотреть, принимать и скрывать заявки в друзья
- Добавлен просмотр популярных комментариев пользователя
- Добавлен блок "Продолжить просмотр" на странице релиза если был произведён вход в аккаунт (3 рандомных релиза из списков сморю, в планах и отложено)
## Изменено
- Стиль некоторых элементов был изменён в связи с обновление библиотеки компонентов
- Блок скриншотов был перенесён на другую библиотеку
- Изменён вид блока связанных релизов на странице релиза с карусели карточек на список
- Изменён блок активности на странице профиля
- Изменены виды блоков "Оценки" и "Недавно просмотренные" на странице профиля с карусели карточек на список
- Изменён вид блока профиля (соц. сети и роли)