mirror of
https://github.com/Radiquum/AniX.git
synced 2025-04-06 00:04:39 +00:00
feat: add changelog modal on visit if new version is detected
This commit is contained in:
parent
04c072fba7
commit
8bcd548ae3
11 changed files with 1137 additions and 22 deletions
5
TODO.md
5
TODO.md
|
@ -1,10 +1,5 @@
|
||||||
# Список TODO для AniX V3
|
# Список TODO для AniX V3
|
||||||
|
|
||||||
## Важное
|
|
||||||
|
|
||||||
- [ ] Кнопка сброса всех настроек
|
|
||||||
- [ ] Список изменений при входе
|
|
||||||
|
|
||||||
## Страницы
|
## Страницы
|
||||||
|
|
||||||
### Поиск
|
### Поиск
|
||||||
|
|
41
app/App.tsx
41
app/App.tsx
|
@ -6,15 +6,34 @@ import { Inter } from "next/font/google";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Button, Modal } from "flowbite-react";
|
import { Button, Modal } from "flowbite-react";
|
||||||
import { Spinner } from "./components/Spinner/Spinner";
|
import { Spinner } from "./components/Spinner/Spinner";
|
||||||
|
import { ChangelogModal } from "#/components/ChangelogModal/ChangelogModal";
|
||||||
|
|
||||||
const inter = Inter({ subsets: ["latin"] });
|
const inter = Inter({ subsets: ["latin"] });
|
||||||
|
|
||||||
export const App = (props) => {
|
export const App = (props) => {
|
||||||
const preferencesStore = usePreferencesStore();
|
const preferencesStore = usePreferencesStore();
|
||||||
const userStore = useUserStore((state) => state);
|
const userStore = useUserStore((state) => state);
|
||||||
|
const [showChangelog, setShowChangelog] = useState(false);
|
||||||
|
const [currentVersion, setCurrentVersion] = useState("");
|
||||||
|
const [previousVersions, setPreviousVersions] = useState([]);
|
||||||
|
|
||||||
|
async function _checkVersion() {
|
||||||
|
const res = await fetch("/api/version");
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (data.version !== preferencesStore.params.version) {
|
||||||
|
setShowChangelog(true);
|
||||||
|
setCurrentVersion(data.version);
|
||||||
|
setPreviousVersions(data.previous);
|
||||||
|
}
|
||||||
|
console.log(data.version, preferencesStore.params.version);
|
||||||
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
userStore.checkAuth();
|
if (preferencesStore._hasHydrated) {
|
||||||
}, []);
|
_checkVersion();
|
||||||
|
userStore.checkAuth();
|
||||||
|
}
|
||||||
|
}, [preferencesStore._hasHydrated]);
|
||||||
|
|
||||||
if (!preferencesStore._hasHydrated && !userStore._hasHydrated) {
|
if (!preferencesStore._hasHydrated && !userStore._hasHydrated) {
|
||||||
return (
|
return (
|
||||||
|
@ -42,7 +61,19 @@ export const App = (props) => {
|
||||||
>
|
>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
{props.children}
|
{props.children}
|
||||||
<Modal show={preferencesStore.params.isFirstLaunch}>
|
<ChangelogModal
|
||||||
|
isOpen={showChangelog && preferencesStore.flags.showChangelog}
|
||||||
|
setIsOpen={() => {
|
||||||
|
setShowChangelog(false);
|
||||||
|
preferencesStore.setParams({ version: currentVersion });
|
||||||
|
}}
|
||||||
|
version={currentVersion}
|
||||||
|
previousVersions={previousVersions}
|
||||||
|
/>
|
||||||
|
<Modal
|
||||||
|
show={preferencesStore.params.isFirstLaunch}
|
||||||
|
onClose={() => preferencesStore.setParams({ isFirstLaunch: false })}
|
||||||
|
>
|
||||||
<Modal.Header>Внимание</Modal.Header>
|
<Modal.Header>Внимание</Modal.Header>
|
||||||
<Modal.Body>
|
<Modal.Body>
|
||||||
<p>
|
<p>
|
||||||
|
@ -61,9 +92,7 @@ export const App = (props) => {
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button
|
<Button
|
||||||
color={"blue"}
|
color={"blue"}
|
||||||
onClick={() => {
|
onClick={() => preferencesStore.setParams({ isFirstLaunch: false })}
|
||||||
preferencesStore.setParams({ isFirstLaunch: false });
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Принимаю
|
Принимаю
|
||||||
</Button>
|
</Button>
|
||||||
|
|
17
app/api/version/route.ts
Normal file
17
app/api/version/route.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import * as fs from "node:fs";
|
||||||
|
import * as path from "node:path";
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
const directoryPath = path.join(process.cwd(), "public/changelog");
|
||||||
|
const files = fs.readdirSync(directoryPath);
|
||||||
|
const current = "3.0.1";
|
||||||
|
const previous = [];
|
||||||
|
files.forEach((file) => {
|
||||||
|
if (file != `${current}.md`) {
|
||||||
|
previous.push(file.replace(".md", ""));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json({ version: current, previous: previous });
|
||||||
|
}
|
16
app/components/ChangelogModal/ChangelogModal.module.css
Normal file
16
app/components/ChangelogModal/ChangelogModal.module.css
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
.markdown h1 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h2 {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-block: 1rem 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown ul {
|
||||||
|
list-style-type: disc;
|
||||||
|
-webkit-padding-start: 20px;
|
||||||
|
padding-inline-start: 20px;
|
||||||
|
}
|
68
app/components/ChangelogModal/ChangelogModal.tsx
Normal file
68
app/components/ChangelogModal/ChangelogModal.tsx
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import { Modal, Button, Accordion } from "flowbite-react";
|
||||||
|
import Markdown from "markdown-to-jsx";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import Styles from "./ChangelogModal.module.css";
|
||||||
|
|
||||||
|
async function _fetchVersionChangelog(version: string) {
|
||||||
|
const res = await fetch(`/changelog/${version}.md`);
|
||||||
|
return await res.text();
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ChangelogModal = (props: {
|
||||||
|
isOpen: boolean;
|
||||||
|
setIsOpen: any;
|
||||||
|
version: string;
|
||||||
|
previousVersions: Array<string>;
|
||||||
|
}) => {
|
||||||
|
const [currentVersionChangelog, setCurrentVersionChangelog] = useState("");
|
||||||
|
const [previousVersionsChangelog, setPreviousVersionsChangelog] = useState<
|
||||||
|
Record<string, string>
|
||||||
|
>({});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
_fetchVersionChangelog(props.version).then((data) => {
|
||||||
|
setCurrentVersionChangelog(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (props.previousVersions.length > 0) {
|
||||||
|
props.previousVersions.forEach((version) => {
|
||||||
|
_fetchVersionChangelog(version).then((data) => {
|
||||||
|
setPreviousVersionsChangelog((prev) => {
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[version]: data,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [props.isOpen]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
show={props.isOpen}
|
||||||
|
onClose={() => props.setIsOpen(false)}
|
||||||
|
>
|
||||||
|
<Modal.Header>Список изменений v{props.version}</Modal.Header>
|
||||||
|
<Modal.Body>
|
||||||
|
<Markdown className={Styles.markdown}>
|
||||||
|
{currentVersionChangelog}
|
||||||
|
</Markdown>
|
||||||
|
{Object.keys(previousVersionsChangelog).length > 0 && (
|
||||||
|
<Accordion collapseAll={true} className="mt-4">
|
||||||
|
{Object.entries(previousVersionsChangelog).map(
|
||||||
|
([version, changelog]) => (
|
||||||
|
<Accordion.Panel key={version}>
|
||||||
|
<Accordion.Title>Список изменений v{version}</Accordion.Title>
|
||||||
|
<Accordion.Content>
|
||||||
|
<Markdown className={Styles.markdown}>{changelog}</Markdown>
|
||||||
|
</Accordion.Content>
|
||||||
|
</Accordion.Panel>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</Accordion>
|
||||||
|
)}
|
||||||
|
</Modal.Body>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
|
@ -7,8 +7,8 @@ import {
|
||||||
Dropdown,
|
Dropdown,
|
||||||
Modal,
|
Modal,
|
||||||
Button,
|
Button,
|
||||||
DarkThemeToggle,
|
|
||||||
useThemeMode,
|
useThemeMode,
|
||||||
|
ToggleSwitch,
|
||||||
} from "flowbite-react";
|
} from "flowbite-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
|
@ -194,7 +194,9 @@ export const Navbar = () => {
|
||||||
>
|
>
|
||||||
<Dropdown.Item className="text-sm md:text-base">
|
<Dropdown.Item className="text-sm md:text-base">
|
||||||
<Link
|
<Link
|
||||||
href={pathname != "/login" ? `/login?redirect=${pathname}` : "#"}
|
href={
|
||||||
|
pathname != "/login" ? `/login?redirect=${pathname}` : "#"
|
||||||
|
}
|
||||||
className="flex items-center gap-1"
|
className="flex items-center gap-1"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
@ -267,6 +269,29 @@ const SettingsModal = (props: { isOpen: boolean; setIsOpen: any }) => {
|
||||||
</Button>
|
</Button>
|
||||||
</Button.Group>
|
</Button.Group>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<p className="font-bold dark:text-white">
|
||||||
|
Показывать список изменений
|
||||||
|
</p>
|
||||||
|
<ToggleSwitch
|
||||||
|
color="blue"
|
||||||
|
theme={{
|
||||||
|
toggle: {
|
||||||
|
checked: {
|
||||||
|
color: {
|
||||||
|
blue: "border-blue-700 bg-blue-700",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onChange={() =>
|
||||||
|
preferenceStore.setFlags({
|
||||||
|
showChangelog: !preferenceStore.flags.showChangelog,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
checked={preferenceStore.flags.showChangelog}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { persist } from "zustand/middleware";
|
import { persist } from "zustand/middleware";
|
||||||
|
import { deepmerge } from "deepmerge-ts";
|
||||||
|
|
||||||
interface preferencesState {
|
interface preferencesState {
|
||||||
_hasHydrated: boolean;
|
_hasHydrated: boolean;
|
||||||
flags: {
|
flags: {
|
||||||
// saveSearchHistory: boolean;
|
// saveSearchHistory: boolean;
|
||||||
saveWatchHistory: boolean;
|
saveWatchHistory?: boolean;
|
||||||
// theme: "light" | "dark" | "black" | "system";
|
showChangelog?: boolean;
|
||||||
};
|
};
|
||||||
params: {
|
params: {
|
||||||
isFirstLaunch: boolean;
|
isFirstLaunch?: boolean;
|
||||||
|
version?: string;
|
||||||
// color: {
|
// color: {
|
||||||
// primary: string;
|
// primary: string;
|
||||||
// secondary: string;
|
// secondary: string;
|
||||||
|
@ -29,10 +31,11 @@ export const usePreferencesStore = create<preferencesState>()(
|
||||||
flags: {
|
flags: {
|
||||||
// saveSearchHistory: true,
|
// saveSearchHistory: true,
|
||||||
saveWatchHistory: true,
|
saveWatchHistory: true,
|
||||||
// theme: "light",
|
showChangelog: true,
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
isFirstLaunch: true,
|
isFirstLaunch: true,
|
||||||
|
version: "3.0.0",
|
||||||
},
|
},
|
||||||
setHasHydrated: (state) => {
|
setHasHydrated: (state) => {
|
||||||
set({
|
set({
|
||||||
|
@ -40,10 +43,10 @@ export const usePreferencesStore = create<preferencesState>()(
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setFlags(flags) {
|
setFlags(flags) {
|
||||||
set({ flags });
|
set({ flags: { ...get().flags, ...flags } });
|
||||||
},
|
},
|
||||||
setParams(params) {
|
setParams(params) {
|
||||||
set({ params });
|
set({ params: { ...get().params, ...params } });
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
|
@ -51,6 +54,9 @@ export const usePreferencesStore = create<preferencesState>()(
|
||||||
onRehydrateStorage: (state) => {
|
onRehydrateStorage: (state) => {
|
||||||
return () => state.setHasHydrated(true);
|
return () => state.setHasHydrated(true);
|
||||||
},
|
},
|
||||||
|
merge: (persistedState , currentState) => {
|
||||||
|
return deepmerge(currentState as preferencesState, persistedState as preferencesState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
929
package-lock.json
generated
929
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -9,8 +9,10 @@
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"deepmerge-ts": "^7.1.0",
|
||||||
"flowbite": "^2.4.1",
|
"flowbite": "^2.4.1",
|
||||||
"flowbite-react": "^0.10.1",
|
"flowbite-react": "^0.10.1",
|
||||||
|
"markdown-to-jsx": "^7.4.7",
|
||||||
"next": "14.2.5",
|
"next": "14.2.5",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
|
@ -26,6 +28,7 @@
|
||||||
"@iconify/tailwind": "^1.1.1",
|
"@iconify/tailwind": "^1.1.1",
|
||||||
"@types/node": "20.14.12",
|
"@types/node": "20.14.12",
|
||||||
"@types/react": "18.3.3",
|
"@types/react": "18.3.3",
|
||||||
|
"copy-webpack-plugin": "^12.0.2",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.5",
|
"eslint-config-next": "14.2.5",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
|
|
19
public/changelog/3.0.0.md
Normal file
19
public/changelog/3.0.0.md
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# 3.0.0
|
||||||
|
|
||||||
|
Это обновление приносит новый интерфейс, а так-же новую систему проксирования запросов API к серверу Anixart.
|
||||||
|
|
||||||
|
## Добавлено
|
||||||
|
|
||||||
|
- Больше информации при просмотре страниц на карточке релиза (рейтинг, статус, категория и т.д.)
|
||||||
|
- адаптация под мобильные устройства
|
||||||
|
- возможность смотреть и ставить оценки релизу
|
||||||
|
- больше информации о самом релизе
|
||||||
|
- просмотр комментариев, их оценка. возможность комментирования и ответа на комментарии.
|
||||||
|
- добавлена страница франшиз\полных связанных релизов
|
||||||
|
- поиск по автору, режиссёру, студии и жанрам
|
||||||
|
- возможность установить сайт как веб приложение
|
||||||
|
|
||||||
|
## Удалено
|
||||||
|
|
||||||
|
- материал ю
|
||||||
|
- не стандартная история поиска
|
14
public/changelog/3.0.1.md
Normal file
14
public/changelog/3.0.1.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# 3.0.1
|
||||||
|
|
||||||
|
## Добавлено
|
||||||
|
|
||||||
|
- Новое уведомление о бане пользователя администрацией
|
||||||
|
- Дисклеймер при первом открытии
|
||||||
|
- Список изменений при открытии
|
||||||
|
|
||||||
|
## Исправлено
|
||||||
|
|
||||||
|
- Вид кнопок социальных сетей в профиле
|
||||||
|
- Сжатие аватарки пользователя при слишком длинном статусе
|
||||||
|
- Перенос текста статуса на новые линии
|
||||||
|
- Загрузка пока авторизация не проверена
|
Loading…
Add table
Reference in a new issue