refactor: replace Menu with new Popup component
This commit is contained in:
parent
5f78b6aa15
commit
cd668fc33a
9 changed files with 104 additions and 80 deletions
|
|
@ -1,8 +1,8 @@
|
|||
import type { ToOptions } from '@tanstack/react-router';
|
||||
import { bindings } from '@/main';
|
||||
import useNotifications from '@/hooks/useNotification';
|
||||
import { bindings } from '@/main';
|
||||
import { useCommand } from '@onelauncher/common';
|
||||
import { Button, Menu } from '@onelauncher/common/components';
|
||||
import { Button, Menu, Popup } from '@onelauncher/common/components';
|
||||
import { Link } from '@tanstack/react-router';
|
||||
import { Bell01Icon, Cloud01Icon, TerminalBrowserIcon } from '@untitled-theme/icons-react';
|
||||
import { MenuTrigger } from 'react-aria-components';
|
||||
|
|
@ -40,7 +40,7 @@ function Navbar() {
|
|||
|
||||
{/* Notification Manager Button */}
|
||||
<div className="relative">
|
||||
<MenuTrigger>
|
||||
<Popup.Trigger>
|
||||
<Button className="relative" color="ghost" size="icon">
|
||||
<Bell01Icon />
|
||||
{notificationCount > 0 && (
|
||||
|
|
@ -49,22 +49,21 @@ function Navbar() {
|
|||
</span>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<Menu.Popover placement="bottom right">
|
||||
<Popup>
|
||||
<NotificationPopup />
|
||||
</Menu.Popover>
|
||||
</MenuTrigger>
|
||||
</Popup>
|
||||
</Popup.Trigger>
|
||||
</div>
|
||||
|
||||
<MenuTrigger>
|
||||
<Popup.Trigger>
|
||||
<Button className="p-0" color="ghost" size="icon">
|
||||
<PlayerHead className="h-full rounded-md hover:opacity-70" uuid={defaultUser.data?.id} />
|
||||
</Button>
|
||||
|
||||
<Menu.Popover>
|
||||
<Popup>
|
||||
<AccountPopup />
|
||||
</Menu.Popover>
|
||||
</MenuTrigger>
|
||||
</Popup>
|
||||
</Popup.Trigger>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@ import Modal from '@/components/overlay/Modal';
|
|||
import ScrollableContainer from '@/components/ScrollableContainer';
|
||||
import { bindings } from '@/main';
|
||||
import { LAUNCHER_IMPORT_TYPES, LOADERS, upperFirst } from '@/utils';
|
||||
import { useCommand } from '@onelauncher/common';
|
||||
import { useCommand, useCommandMut } from '@onelauncher/common';
|
||||
import { Button, Dropdown, SelectList, TextField } from '@onelauncher/common/components';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { ArrowRightIcon, PlusIcon, SearchMdIcon, Server01Icon, TextInputIcon, User03Icon } from '@untitled-theme/icons-react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { Checkbox } from 'react-aria-components';
|
||||
|
|
@ -34,29 +33,22 @@ export function NewClusterCreate() {
|
|||
clusterVersion: '',
|
||||
});
|
||||
|
||||
const create = useCommand('createCluster', () => bindings.core.createCluster({
|
||||
const create = useCommandMut(() => bindings.core.createCluster({
|
||||
icon: DefaultClusterBanner,
|
||||
mc_loader: formData.loader as GameLoader,
|
||||
mc_loader_version: null,
|
||||
mc_version: formData.clusterVersion,
|
||||
name: formData.clusterName,
|
||||
}), {
|
||||
enabled: false,
|
||||
subscribed: false,
|
||||
});
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
}));
|
||||
|
||||
function handleCreate() {
|
||||
if (!isLastInputStep)
|
||||
return;
|
||||
|
||||
create.refetch();
|
||||
create.mutate();
|
||||
|
||||
if (create.isError)
|
||||
console.error(create.error.message);
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ['getClusters'], exact: true });
|
||||
}
|
||||
|
||||
const handleNext = useCallback(async () => {
|
||||
|
|
|
|||
|
|
@ -2,58 +2,61 @@ import type { MinecraftCredentials } from '@/bindings.gen';
|
|||
import PlayerHead from '@/components/content/PlayerHead';
|
||||
import { bindings } from '@/main';
|
||||
import { useCommand } from '@onelauncher/common';
|
||||
import { Button, Menu } from '@onelauncher/common/components';
|
||||
import { Button } from '@onelauncher/common/components';
|
||||
import { Link } from '@tanstack/react-router';
|
||||
import { PlusIcon, Settings01Icon } from '@untitled-theme/icons-react';
|
||||
import { Separator } from 'react-aria-components';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
function AccountPopup() {
|
||||
const users = useCommand('getUsers', bindings.core.getUsers);
|
||||
const defaultUser = useCommand('getDefaultUser', () => bindings.core.getDefaultUser(false));
|
||||
|
||||
const addAccount = useCommand('openMsaLogin', bindings.core.openMsaLogin, {
|
||||
enabled: false,
|
||||
subscribed: false,
|
||||
});
|
||||
|
||||
const setDefaultUser = (user: MinecraftCredentials) => {
|
||||
bindings.core.setDefaultUser(user.id);
|
||||
};
|
||||
|
||||
return (
|
||||
<Menu className="min-w-3xs">
|
||||
<div className="min-w-3xs">
|
||||
{defaultUser.data && (
|
||||
<Menu.Item>
|
||||
<div>
|
||||
<AccountEntry
|
||||
loggedIn
|
||||
onClick={() => {}}
|
||||
onClick={() => { }}
|
||||
user={defaultUser.data}
|
||||
/>
|
||||
</Menu.Item>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{users.data?.filter(user => user.id === defaultUser.data?.id).map(user => (
|
||||
<Menu.Item key={user.id}>
|
||||
{users.data?.filter(user => user.id !== defaultUser.data?.id).map(user => (
|
||||
<div key={user.id}>
|
||||
<AccountEntry
|
||||
onClick={() => setDefaultUser(user)}
|
||||
user={user}
|
||||
/>
|
||||
</Menu.Item>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{(users.data?.length ?? 0) > 0 && (
|
||||
<Separator />
|
||||
)}
|
||||
|
||||
<Menu.Item className="flex flex-row justify-between">
|
||||
<div>
|
||||
<Button color="ghost">
|
||||
<div className="flex flex-row justify-between">
|
||||
<div className="self-center">
|
||||
<Button color="ghost" onClick={() => addAccount.refetch()}>
|
||||
<PlusIcon />
|
||||
Add Account
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-row">
|
||||
<Button color="ghost" size="iconLarge">
|
||||
<Settings01Icon className="stroke-fg-primary" />
|
||||
</Button>
|
||||
<Link to="/app/settings/accounts">
|
||||
<Button color="ghost" size="iconLarge">
|
||||
<Settings01Icon className="stroke-fg-primary" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import type { NotificationData } from '@/hooks/useNotification';
|
||||
import useNotifications from '@/hooks/useNotification';
|
||||
import { Button, Menu } from '@onelauncher/common/components';
|
||||
import { Button, Menu, Popup } from '@onelauncher/common/components';
|
||||
import { XIcon } from '@untitled-theme/icons-react';
|
||||
import { Popover } from 'react-aria-components';
|
||||
|
||||
interface NotificationItemProps {
|
||||
id: string;
|
||||
|
|
@ -53,35 +54,29 @@ function NotificationPopup() {
|
|||
|
||||
if (notificationEntries.length === 0)
|
||||
return (
|
||||
<Menu className="min-w-80 max-w-96">
|
||||
<Menu.Item>
|
||||
<div className="p-4 text-center">
|
||||
<p className="text-fg-secondary text-sm">No notifications</p>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
<div className="p-3 text-center">
|
||||
<p className="text-fg-secondary text-sm">No notifications</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Menu className="min-w-80 max-w-96 max-h-96 overflow-y-auto">
|
||||
<Menu.Item>
|
||||
<div className="flex items-center justify-between p-3 border-b border-component-border">
|
||||
<h3 className="font-semibold text-fg-primary">Notifications</h3>
|
||||
{notificationEntries.length > 0 && (
|
||||
<Button
|
||||
className="text-xs"
|
||||
color="ghost"
|
||||
onClick={clear}
|
||||
size="normal"
|
||||
>
|
||||
Clear All
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</Menu.Item>
|
||||
<Popup className="min-w-80 w-full max-w-96 max-h-96 overflow-y-auto">
|
||||
<div className="flex items-center justify-between border-b border-component-border">
|
||||
<h3 className="font-semibold text-fg-primary">Notifications</h3>
|
||||
{notificationEntries.length > 0 && (
|
||||
<Button
|
||||
className="text-xs"
|
||||
color="ghost"
|
||||
onClick={clear}
|
||||
size="normal"
|
||||
>
|
||||
Clear All
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{notificationEntries.map(([id, data]) => (
|
||||
<Menu.Item key={id}>
|
||||
<div key={id}>
|
||||
<div className="p-2">
|
||||
<NotificationItem
|
||||
data={data}
|
||||
|
|
@ -89,9 +84,9 @@ function NotificationPopup() {
|
|||
onRemove={removeNotification}
|
||||
/>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
</div>
|
||||
))}
|
||||
</Menu>
|
||||
</Popup>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,13 +43,8 @@ export function NotificationProvider({ children }: NotificationProviderProps) {
|
|||
}));
|
||||
}).then(u => u());
|
||||
|
||||
const ctx = {
|
||||
notifications,
|
||||
setNotifications,
|
||||
};
|
||||
|
||||
return (
|
||||
<NotificationContext.Provider value={ctx}>
|
||||
<NotificationContext.Provider value={{ notifications, setNotifications }}>
|
||||
{children}
|
||||
</NotificationContext.Provider>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import DefaultInstancePhoto from '@/assets/images/default_instance_cover.jpg';
|
|||
import LoaderIcon from '@/components/launcher/LoaderIcon';
|
||||
import ScrollableContainer from '@/components/ScrollableContainer';
|
||||
import SettingsRow from '@/components/SettingsRow';
|
||||
import useNotifications from '@/hooks/useNotification';
|
||||
import { bindings } from '@/main';
|
||||
import { useCommand } from '@onelauncher/common';
|
||||
import { Button, Show, TextField } from '@onelauncher/common/components';
|
||||
|
|
@ -129,6 +130,8 @@ function Banner({
|
|||
setNewName,
|
||||
setNewCover,
|
||||
}: BannerProps) {
|
||||
const { set, list } = useNotifications();
|
||||
|
||||
async function launchFilePicker() {
|
||||
const selected = await open({
|
||||
multiple: false,
|
||||
|
|
@ -153,8 +156,17 @@ function Banner({
|
|||
const handleLaunch = () => {
|
||||
launch.refetch();
|
||||
|
||||
if (launch.error)
|
||||
console.error(launch.error.message);
|
||||
// eslint-disable-next-line no-console -- debug
|
||||
console.log(list);
|
||||
|
||||
if (launch.isError)
|
||||
set('launch_cluster', {
|
||||
title: 'Failed to launch cluster',
|
||||
message: launch.error.message,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-console -- debug
|
||||
console.log(list);
|
||||
};
|
||||
|
||||
function updateName(name: string) {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@ function RouteComponent() {
|
|||
const { data: usersData, isLoading: usersLoading } = useCommand('getUsers', bindings.core.getUsers);
|
||||
const { data: defaultUserData, isLoading: defaultUserLoading } = useCommand('getDefaultUser', () => bindings.core.getDefaultUser(false));
|
||||
|
||||
const addAccount = useCommand('openMsaLogin', bindings.core.openMsaLogin, {
|
||||
enabled: false,
|
||||
subscribed: false,
|
||||
});
|
||||
|
||||
if (usersLoading || defaultUserLoading)
|
||||
return (
|
||||
<Sidebar.Page>
|
||||
|
|
@ -47,7 +52,7 @@ function RouteComponent() {
|
|||
</ScrollableContainer>
|
||||
|
||||
<div className="mt-auto pt-2 flex flex-row items-end justify-end">
|
||||
<Button color="primary">
|
||||
<Button color="primary" onClick={() => addAccount.refetch()}>
|
||||
<UserPlus02Icon />
|
||||
{' '}
|
||||
Add Account
|
||||
|
|
|
|||
22
packages/web_common/src/components/Popup.tsx
Normal file
22
packages/web_common/src/components/Popup.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import type { PopoverProps } from 'react-aria-components';
|
||||
import { Dialog, DialogTrigger, Popover } from 'react-aria-components';
|
||||
|
||||
interface MyPopoverProps extends Omit<PopoverProps, 'children'> {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function Popup({ children, ...props }: MyPopoverProps) {
|
||||
return (
|
||||
<Popover {...props} className="flex flex-col gap-0.5 rounded-lg border border-component-border">
|
||||
<Dialog className="bg-page-elevated p-2 shadow-md rounded-lg">
|
||||
{children}
|
||||
</Dialog>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
function Trigger({ children, ...props }: any) {
|
||||
return <DialogTrigger children={children} {...props} />;
|
||||
}
|
||||
|
||||
Popup.Trigger = Trigger;
|
||||
|
|
@ -3,6 +3,7 @@ export * from './Button';
|
|||
export * from './ContextMenu';
|
||||
export * from './Dropdown';
|
||||
export * from './Menu';
|
||||
export * from './Popup';
|
||||
export * from './SelectList';
|
||||
export * from './Show';
|
||||
export * from './Switch';
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue