Replace shadcn-ui with HeroUI components

This commit is contained in:
grimsi
2025-03-18 16:31:16 +01:00
parent 84a90d41ea
commit 4dc709660d
28 changed files with 240 additions and 848 deletions
-17
View File
@@ -1,17 +0,0 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/main/frontend/main.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
import {NextUIPluginConfig} from "@heroui/react";
import {HeroUIPluginConfig} from "@heroui/react";
import {compileThemes, themes} from "./src/main/frontend/theming/themes"
export const NextUIConfig: NextUIPluginConfig = {
export const HeroUIConfig: HeroUIPluginConfig = {
prefix: "gf",
themes: compileThemes(themes)
};
+58 -632
View File
File diff suppressed because it is too large Load Diff
+6 -12
View File
@@ -3,10 +3,11 @@
"version": "2.0.0-ALPHA",
"type": "module",
"dependencies": {
"@material-tailwind/react": "^2.1.10",
"@heroui/react": "2.7.5",
"@material-tailwind/react": "^2.1.10",
"@phosphor-icons/react": "^2.1.7",
"@polymer/polymer": "3.5.2",
"@react-types/shared": "^3.28.0",
"@vaadin/bundles": "24.6.6",
"@vaadin/common-frontend": "0.0.19",
"@vaadin/hilla-file-router": "24.6.6",
@@ -24,9 +25,7 @@
"@vaadin/vaadin-material-styles": "24.6.6",
"@vaadin/vaadin-themable-mixin": "24.6.6",
"@vaadin/vaadin-usage-statistics": "2.1.3",
"class-variance-authority": "^0.7.0",
"classnames": "^2.5.1",
"clsx": "^2.1.1",
"construct-style-sheets-polyfill": "3.1.0",
"cron-validator": "^1.3.1",
"date-fns": "2.29.3",
@@ -41,8 +40,6 @@
"react-confetti-boom": "^1.0.0",
"react-dom": "18.3.1",
"react-router-dom": "6.29.0",
"sonner": "^1.7.1",
"tailwind-merge": "^2.5.2",
"yup": "^1.6.1"
},
"devDependencies": {
@@ -96,14 +93,10 @@
"@phosphor-icons/react": "$@phosphor-icons/react",
"formik": "$formik",
"yup": "$yup",
"class-variance-authority": "$class-variance-authority",
"clsx": "$clsx",
"next-themes": "$next-themes",
"tailwind-merge": "$tailwind-merge",
"@heroui/react": "$@heroui/react",
"framer-motion": "$framer-motion",
"@material-tailwind/react": "$@material-tailwind/react",
"sonner": "$sonner",
"http-status-codes": "$http-status-codes",
"@vaadin/polymer-legacy-adapter": "$@vaadin/polymer-legacy-adapter",
"@vaadin/vaadin-development-mode-detector": "$@vaadin/vaadin-development-mode-detector",
@@ -124,7 +117,8 @@
"date-fns": "$date-fns",
"@vaadin/vaadin-themable-mixin": "$@vaadin/vaadin-themable-mixin",
"@vaadin/vaadin-lumo-styles": "$@vaadin/vaadin-lumo-styles",
"@vaadin/vaadin-material-styles": "$@vaadin/vaadin-material-styles"
"@vaadin/vaadin-material-styles": "$@vaadin/vaadin-material-styles",
"@react-types/shared": "$@react-types/shared"
},
"vaadin": {
"dependencies": {
@@ -184,6 +178,6 @@
"workbox-core": "7.3.0",
"workbox-precaching": "7.3.0"
},
"hash": "4cb8eb38282e90ab28af32f01ad7d2f7a15758837309655a753bbc1989258d6f"
"hash": "3f65776fc466d9436093cb2be8081f16d86234693e52c66dcc7faf5ad0bfbee6"
}
}
}
@@ -1,58 +0,0 @@
import * as React from "react"
import {cva, type VariantProps} from "class-variance-authority"
import {cn} from "Frontend/util/utils";
const alertVariants = cva(
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
{
variants: {
variant: {
default: "bg-background text-foreground",
destructive:
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
},
},
defaultVariants: {
variant: "default",
},
}
)
const Alert = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
>(({className, variant, ...props}, ref) => (
<div
ref={ref}
role="alert"
className={cn(alertVariants({variant}), className)}
{...props}
/>
))
Alert.displayName = "Alert"
const AlertTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({className, ...props}, ref) => (
<h5
ref={ref}
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...props}
/>
))
AlertTitle.displayName = "AlertTitle"
const AlertDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({className, ...props}, ref) => (
<div
ref={ref}
className={cn("text-sm [&_p]:leading-relaxed", className)}
{...props}
/>
))
AlertDescription.displayName = "AlertDescription"
export {Alert, AlertTitle, AlertDescription}
@@ -1,29 +0,0 @@
import { useTheme } from "next-themes"
import { Toaster as Sonner } from "sonner"
type ToasterProps = React.ComponentProps<typeof Sonner>
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme()
return (
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
toastOptions={{
classNames: {
toast:
"group toast group-[.toaster]:bg-content1 group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
description: "group-[.toast]:text-muted-foreground",
actionButton:
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
cancelButton:
"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
},
}}
{...props}
/>
)
}
export { Toaster }
+16 -3
View File
@@ -2,11 +2,11 @@ import {Outlet, useHref, useNavigate} from 'react-router-dom';
import "./main.css";
import "Frontend/util/custom-validators";
import {HeroUIProvider} from "@heroui/react";
import {ToastProvider} from "@heroui/toast";
import {ThemeProvider as NextThemesProvider} from "next-themes";
import {themeNames} from "Frontend/theming/themes";
import {AuthProvider} from "Frontend/util/auth";
import {IconContext} from "@phosphor-icons/react";
import {Toaster} from "Frontend/@/components/ui/sonner";
import {IconContext, X} from "@phosphor-icons/react";
import client from "Frontend/generated/connect-client.default";
import {ErrorHandlingMiddleware} from "Frontend/util/middleware";
@@ -21,7 +21,20 @@ export default function App() {
<AuthProvider>
<IconContext.Provider value={{size: 20}}>
<Outlet/>
<Toaster/>
<ToastProvider
toastProps={{
shouldShowTimeoutProgress: true,
radius: "sm",
variant: "flat",
hideIcon: true,
closeIcon: <X/>,
classNames: {
closeButton: "opacity-100 absolute right-4 top-1/2 -translate-y-1/2",
progressTrack: "h-1",
}
}}
toastOffset={64}
/>
</IconContext.Provider>
</AuthProvider>
</NextThemesProvider>
@@ -67,7 +67,7 @@ export default function ProfileMenu() {
return (
<DropdownItem
key={label}
onClick={onClick}
onPress={onClick}
startContent={<div color={color}>{icon}</div>}
/* @ts-ignore */
color={color ? color : ""}
@@ -3,8 +3,7 @@ import {LogEndpoint} from "Frontend/generated/endpoints";
import withConfigPage from "Frontend/components/administration/withConfigPage";
import * as Yup from 'yup';
import ConfigFormField from "Frontend/components/administration/ConfigFormField";
import {toast} from "sonner";
import {Button, Code, Divider, Tooltip} from "@heroui/react";
import {addToast, Button, Code, Divider, Tooltip} from "@heroui/react";
import {ArrowUDownLeft, SortAscending} from "@phosphor-icons/react";
function LogManagementLayout({getConfig, formik}: any) {
@@ -24,7 +23,11 @@ function LogManagementLayout({getConfig, formik}: any) {
useEffect(() => {
if (formik.isSubmitting == false && formik.submitCount > 0) {
LogEndpoint.reloadLogConfig()
.catch(() => toast.error("Failed to apply log configuration"));
.catch(() => addToast({
title: "Error",
description: "Failed to apply log configuration",
color: "danger"
}));
}
}, [formik.isSubmitting]);
@@ -2,9 +2,8 @@ import React, {useEffect, useState} from "react";
import withConfigPage from "Frontend/components/administration/withConfigPage";
import ConfigFormField from "Frontend/components/administration/ConfigFormField";
import Section from "Frontend/components/general/Section";
import {Button, Card, Tooltip, useDisclosure} from "@heroui/react";
import {addToast, Button, Card, Tooltip, useDisclosure} from "@heroui/react";
import {MessageEndpoint, MessageTemplateEndpoint} from "Frontend/generated/endpoints";
import {toast} from "sonner";
import {PaperPlaneRight, Pencil} from "@phosphor-icons/react";
import MessageTemplateDto from "Frontend/generated/de/grimsi/gameyfin/messages/templates/MessageTemplateDto";
import SendTestNotificationModal from "Frontend/components/administration/messages/SendTestNotificationModal";
@@ -34,9 +33,15 @@ function MessageManagementLayout({getConfig, getConfigs, formik}: any) {
const areCredentialsValid = await MessageEndpoint.verifyCredentials(provider, credentials);
if (areCredentialsValid) {
toast.success("Credentials are valid")
addToast({
title: "Credentials are valid",
color: "success"
});
} else {
toast.error("Credentials are invalid")
addToast({
title: "Credentials are invalid",
color: "warning"
});
}
}
@@ -1,6 +1,6 @@
import Section from "Frontend/components/general/Section";
import Input from "Frontend/components/general/Input";
import {Button, Input as NextUiInput, Tooltip} from "@heroui/react";
import {addToast, Button, Input as NextUiInput, Tooltip} from "@heroui/react";
import {Form, Formik} from "formik";
import {ArrowCounterClockwise, Check, Info, Trash} from "@phosphor-icons/react";
import React, {useEffect, useState} from "react";
@@ -9,7 +9,6 @@ import * as Yup from "yup";
import UserUpdateDto from "Frontend/generated/de/grimsi/gameyfin/users/dto/UserUpdateDto";
import {EmailConfirmationEndpoint, MessageEndpoint, UserEndpoint} from "Frontend/generated/endpoints";
import {SmallInfoField} from "Frontend/components/general/SmallInfoField";
import {toast} from "sonner";
import {removeAvatar, uploadAvatar} from "Frontend/endpoints/AvatarEndpoint";
import Avatar from "Frontend/components/general/Avatar";
@@ -48,8 +47,10 @@ export default function ProfileManagement() {
setConfigSaved(true);
if (values.newPassword.length > 0) {
toast.success("Password changed", {
description: "Please log in again"
addToast({
title: "Password changed",
description: "Please log in again",
color: "success"
});
setTimeout(() => {
auth.logout();
@@ -133,7 +134,11 @@ export default function ProfileManagement() {
<Button isIconOnly
onPress={() => {
EmailConfirmationEndpoint.resendEmailConfirmation().then(
() => toast.success("You will receive an email shortly")
() => addToast({
title: "Email confirmation message sent",
description: "Please check your inbox",
color: "success"
})
)
}}
isDisabled={!messagesEnabled}
@@ -3,9 +3,8 @@ import withConfigPage from "Frontend/components/administration/withConfigPage";
import * as Yup from 'yup';
import ConfigFormField from "Frontend/components/administration/ConfigFormField";
import Section from "Frontend/components/general/Section";
import {Button} from "@heroui/react";
import {addToast, Button} from "@heroui/react";
import {MagicWand} from "@phosphor-icons/react";
import {toast} from "sonner";
function SsoManagementLayout({getConfig, formik, setSaveMessage}: any) {
@@ -35,7 +34,10 @@ function SsoManagementLayout({getConfig, formik, setSaveMessage}: any) {
formik.setFieldValue("sso.oidc.logout-url", data.end_session_endpoint);
formik.setFieldValue("sso.oidc.jwks-url", data.jwks_uri);
} catch (e) {
toast.error("Failed to auto-populate SSO configuration");
addToast({
title: "Failed to auto-populate SSO configuration",
color: "warning"
});
}
}
@@ -1,5 +1,6 @@
import React, {useEffect, useState} from "react";
import {
addToast,
Button,
Chip,
Link,
@@ -10,7 +11,6 @@ import {
ModalHeader,
Textarea
} from "@heroui/react";
import {toast} from "sonner";
import {MessageTemplateEndpoint} from "Frontend/generated/endpoints";
import MessageTemplateDto from "Frontend/generated/de/grimsi/gameyfin/messages/templates/MessageTemplateDto";
import TemplateType from "Frontend/generated/de/grimsi/gameyfin/messages/templates/TemplateType";
@@ -111,7 +111,11 @@ export default function EditTemplateModal({isOpen, onOpenChange, selectedTemplat
onPress={async () => {
if (selectedTemplate) {
await saveTemplate(selectedTemplate);
toast.success("Template saved");
addToast({
title: "Template saved",
description: "Template has been saved",
color: "success"
});
onClose();
}
}}>
@@ -1,7 +1,6 @@
import React from "react";
import {Form, Formik} from "formik";
import {Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
import {toast} from "sonner";
import {addToast, Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
import Input from "Frontend/components/general/Input";
import {MessageEndpoint} from "Frontend/generated/endpoints";
import * as Yup from "yup";
@@ -37,7 +36,11 @@ export default function SendTestNotificationModal({
isInitialValid={false}
onSubmit={async (values) => {
await MessageEndpoint.sendTestNotification(selectedTemplate?.key, values);
toast.success("Test notification to you has been sent");
addToast({
title: "Notification sent",
description: "Test notification to you has been sent",
color: "success"
});
onClose();
}}
validationSchema={generateValidationSchema(selectedTemplate?.availablePlaceholders as string[])}
@@ -1,7 +1,6 @@
import React, {useEffect, useState} from "react";
import {Button, Input, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
import {addToast, Button, Input, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
import {RegistrationEndpoint, UserEndpoint} from "Frontend/generated/endpoints";
import {toast} from "sonner";
interface InviteUserModalProps {
isOpen: boolean;
@@ -27,7 +26,11 @@ export default function InviteUserModal({isOpen, onOpenChange}: InviteUserModalP
try {
await RegistrationEndpoint.createInvitation(email);
toast.success("Invitation has been sent");
addToast({
title: "Invitation sent",
description: "The user will receive an email with further instructions shortly.",
color: "success"
});
onClose();
} catch (e) {
setError("Failed to create invitation");
@@ -1,9 +1,8 @@
import React, {useEffect, useState} from "react";
import {Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
import {addToast, Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
import {Input as NextInput} from "@heroui/input";
import {WarningCircle} from "@phosphor-icons/react";
import {MessageEndpoint, PasswordResetEndpoint} from "Frontend/generated/endpoints";
import {toast} from "sonner";
interface PasswordResetModalProps {
isOpen: boolean;
@@ -23,7 +22,11 @@ export default function PasswordResetModal({
async function resetPassword() {
await PasswordResetEndpoint.requestPasswordReset(resetEmail);
toast.success("If the email address is registered, you will receive a message with further instructions.");
addToast({
title: "Password reset requested",
description: "If the email address is registered, you will receive a message with further instructions.",
color: "success"
});
}
return (
@@ -1,6 +1,5 @@
import React, {useEffect, useState} from "react";
import {Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
import {toast} from "sonner";
import {addToast, Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
import {Form, Formik} from "formik";
import {PluginConfigEndpoint, PluginManagementEndpoint} from "Frontend/generated/endpoints";
import PluginDto from "Frontend/generated/de/grimsi/gameyfin/core/plugins/management/PluginDto";
@@ -32,7 +31,11 @@ export default function PluginDetailsModal({plugin, isOpen, onOpenChange, update
async function saveConfig(values: Record<string, string>) {
await PluginConfigEndpoint.setConfigEntries(plugin.id, values);
toast.success(`Configuration for ${plugin.name} saved!`);
addToast({
title: "Configuration saved",
description: `Configuration for plugin ${plugin.name} saved!`,
color: "success"
});
let updatedPlugin = await PluginManagementEndpoint.getPlugin(plugin.id);
if (updatedPlugin === undefined) return;
updatePlugin(updatedPlugin);
@@ -17,7 +17,7 @@ const SelectInput = ({label, values, ...props}) => {
disallowEmptySelection
>
{values.map((value: string) => (
<SelectItem key={value} value={value}>
<SelectItem key={value}>
{value}
</SelectItem>
))}
@@ -1,11 +1,10 @@
import React from "react";
import {Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
import {addToast, Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader} from "@heroui/react";
import {RegistrationEndpoint} from "Frontend/generated/endpoints";
import UserRegistrationDto from "Frontend/generated/de/grimsi/gameyfin/users/dto/UserRegistrationDto";
import {Form, Formik} from "formik";
import * as Yup from "yup";
import Input from "Frontend/components/general/Input";
import {toast} from "sonner";
interface SignUpModalProps {
isOpen: boolean;
@@ -24,12 +23,20 @@ export default function SignUpModal({
password: registration.password,
email: registration.email
});
onClose();
toast.success('You will receive an email with further instructions shortly.');
addToast({
title: "Account created",
description: "You will receive an email with further instructions shortly.",
color: "success"
});
} catch (_) {
toast.error('An error occurred while registering your account.');
addToast({
title: "Registration failed",
description: "An error occurred while registering your account.",
color: "danger"
});
return;
}
}
@@ -1,5 +1,5 @@
import {fetchWithAuth} from "Frontend/util/utils";
import {toast} from "sonner";
import {addToast} from "@heroui/react";
export async function uploadAvatar(avatar: any) {
const formData = new FormData();
@@ -12,7 +12,11 @@ export async function uploadAvatar(avatar: any) {
if (response.ok) {
window.location.reload();
} else {
toast.error("Error uploading avatar", {description: result});
addToast({
title: "Error uploading avatar",
description: result,
color: "danger"
});
}
}
@@ -24,7 +28,11 @@ export async function removeAvatar() {
if (response.ok) {
window.location.reload();
} else {
toast.error("Error removing avatar", {description: result});
addToast({
title: "Error removing avatar",
description: result,
color: "danger"
});
}
}
@@ -36,6 +44,10 @@ export async function removeAvatarByName(name: string) {
if (response.ok) {
window.location.reload();
} else {
toast.error("Error removing avatar", {description: result});
addToast({
title: "Error removing avatar",
description: result,
color: "danger"
});
}
}
+11 -3
View File
@@ -1,5 +1,5 @@
import {Middleware, MiddlewareContext, MiddlewareNext} from '@vaadin/hilla-frontend';
import {toast} from "sonner";
import {addToast} from "@heroui/react";
import {getReasonPhrase} from "http-status-codes";
export const ErrorHandlingMiddleware: Middleware = async function (
@@ -21,9 +21,17 @@ export const ErrorHandlingMiddleware: Middleware = async function (
let json: any = await response.json();
if (json.type == "dev.hilla.exception.EndpointException") {
toast.error(`${getReasonPhrase(response.status)}`, {description: `${json.message}`});
addToast({
title: getReasonPhrase(response.status),
description: json.message,
color: "danger"
})
} else {
toast.error(`${getReasonPhrase(response.status)}`, {description: `${endpoint}.${method}`})
addToast({
title: getReasonPhrase(response.status),
description: `${endpoint}.${method}`,
color: "danger"
})
}
}
-6
View File
@@ -1,12 +1,6 @@
import {type ClassValue, clsx} from "clsx"
import {twMerge} from "tailwind-merge"
import {getCsrfToken} from "Frontend/util/auth";
import moment from 'moment-timezone';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
export function cssVar(variable: string) {
return getComputedStyle(document.documentElement).getPropertyValue(`--${variable}`);
}
@@ -1,4 +1,4 @@
import {Button, Card, CardBody, CardHeader} from "@heroui/react";
import {addToast, Button, Card, CardBody, CardHeader} from "@heroui/react";
import {useNavigate, useSearchParams} from "react-router-dom";
import {Form, Formik} from "formik";
import Input from "Frontend/components/general/Input";
@@ -6,7 +6,6 @@ import * as Yup from "yup";
import {RegistrationEndpoint} from "Frontend/generated/endpoints";
import React, {useEffect, useState} from "react";
import {Warning} from "@phosphor-icons/react";
import {toast} from "sonner";
import UserInvitationAcceptanceResult
from "Frontend/generated/de/grimsi/gameyfin/users/enums/UserInvitationAcceptanceResult";
@@ -33,19 +32,31 @@ export default function InvitationRegistrationView() {
switch (result) {
case UserInvitationAcceptanceResult.SUCCESS:
toast.success("Registration successful");
addToast({
title: "Registration successful",
description: "Your account has been created",
color: "success"
});
navigate("/", {replace: true});
break;
case UserInvitationAcceptanceResult.USERNAME_TAKEN:
formik.setFieldError("username", "Username is already taken");
break;
case UserInvitationAcceptanceResult.TOKEN_EXPIRED:
toast.error("Token is expired");
addToast({
title: "Token expired",
description: "Token is expired",
color: "warning"
});
break;
case UserInvitationAcceptanceResult.TOKEN_INVALID:
default:
toast.error("Token is invalid");
break
addToast({
title: "Invalid token",
description: "Token is invalid",
color: "danger"
});
break;
}
}
@@ -1,4 +1,4 @@
import {Button, Card, CardBody, CardHeader} from "@heroui/react";
import {addToast, Button, Card, CardBody, CardHeader} from "@heroui/react";
import {useNavigate, useSearchParams} from "react-router-dom";
import {Form, Formik} from "formik";
import Input from "Frontend/components/general/Input";
@@ -6,7 +6,6 @@ import * as Yup from "yup";
import {PasswordResetEndpoint} from "Frontend/generated/endpoints";
import React, {useEffect, useState} from "react";
import {Warning} from "@phosphor-icons/react";
import {toast} from "sonner";
import TokenValidationResult from "Frontend/generated/de/grimsi/gameyfin/shared/token/TokenValidationResult";
export default function PasswordResetView() {
@@ -25,15 +24,27 @@ export default function PasswordResetView() {
switch (result) {
case TokenValidationResult.VALID:
toast.success("Password reset successfully");
addToast({
title: "Password reset",
description: "Password reset successfully",
color: "success"
})
navigate("/", {replace: true});
break;
case TokenValidationResult.EXPIRED:
toast.error("Token is expired");
addToast({
title: "Token expired",
description: "Token is expired",
color: "warning"
})
break;
case TokenValidationResult.INVALID:
default:
toast.error("Token is invalid");
addToast({
title: "Invalid token",
description: "Token is invalid",
color: "danger"
})
break
}
}
@@ -4,11 +4,10 @@ import Wizard from "Frontend/components/wizard/Wizard";
import WizardStep from "Frontend/components/wizard/WizardStep";
import Input from "Frontend/components/general/Input";
import {HandWaving, Palette, User} from "@phosphor-icons/react";
import {Card} from "@heroui/react";
import {addToast, Card} from "@heroui/react";
import {SetupEndpoint} from "Frontend/generated/endpoints";
import {ThemeSelector} from "Frontend/components/theming/ThemeSelector";
import {useNavigate} from "react-router-dom";
import {toast} from "sonner";
function WelcomeStep() {
return (
@@ -91,7 +90,11 @@ function SetupView() {
password: values.password,
email: values.email
});
toast.success("Setup finished", {description: "Have fun with Gameyfin!"});
addToast({
title: "Setup finished",
description: "Have fun with Gameyfin!",
color: "success"
})
navigate('/login');
}
}
+16 -24
View File
@@ -1,6 +1,5 @@
import {Link} from "react-router-dom";
import {Button, Input} from "@heroui/react";
import {toast} from "sonner";
import {addToast, Button, Input} from "@heroui/react";
import {LibraryEndpoint, SystemEndpoint} from "Frontend/generated/endpoints";
import {useState} from "react";
import GameDto from "Frontend/generated/de/grimsi/gameyfin/games/dto/GameDto";
@@ -23,32 +22,25 @@ export default function TestView() {
<Link to="/setup">Setup</Link>
<div className="flex flex-row gap-4">
<Button onPress={
() => toast("Normal", {
description: "Description",
action: {
label: "OK",
onClick: () => {
},
}
})}>Toast (Normal)</Button>
() => addToast({
title: "Primary",
description: "Description"
})
}>Toast (Normal)</Button>
<Button onPress={
() => toast.success("Success", {
() => addToast({
title: "Success",
description: "Description",
action: {
label: "OK",
onClick: () => {
},
}
})}>Toast (Success)</Button>
color: "success"
})
}>Toast (Success)</Button>
<Button onPress={
() => toast.error("Error", {
() => addToast({
title: "Error",
description: "Description",
action: {
label: "OK",
onClick: () => {
},
}
})}>Toast (Error)</Button>
color: "danger"
})
}>Toast (Error)</Button>
</div>
<Button onPress={() => SystemEndpoint.restart()}>Restart</Button>
<div className="flex flex-row gap-4 items-center">
+2 -2
View File
@@ -1,6 +1,6 @@
import {Config} from "tailwindcss/types/config";
import {heroui} from "@heroui/react";
import {NextUIConfig} from "./nextui";
import {HeroUIConfig} from "./nextui";
import withMT from "@material-tailwind/react/utils/withMT";
export default withMT({
@@ -22,6 +22,6 @@ export default withMT({
}
},
plugins: [
heroui(NextUIConfig)
heroui(HeroUIConfig)
],
} satisfies Config);
-6
View File
@@ -1,6 +0,0 @@
{
"name": "gameyfin",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}