Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { GameLoader, Version } from '@/bindings.gen';
import type { JSX, RefAttributes } from 'react';
import DefaultBanner from '@/assets/images/default_banner.png';
import LauncherIcon from '@/components/content/LauncherIcon';
import Modal from '@/components/overlay/Modal';
import ScrollableContainer from '@/components/ScrollableContainer';
Expand All @@ -9,7 +8,7 @@ import { LAUNCHER_IMPORT_TYPES, LOADERS, upperFirst } from '@/utils';
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 { PlusIcon, SearchMdIcon, Server01Icon, TextInputIcon, User03Icon } from '@untitled-theme/icons-react';
import { useCallback, useMemo, useState } from 'react';
import { Checkbox } from 'react-aria-components';
import LoaderIcon from '../LoaderIcon';
Expand Down Expand Up @@ -171,14 +170,18 @@ export function NewClusterCreate() {

<Modal isDismissable isOpen={isModalOpen} onOpenChange={setIsModalOpen}>
<div className="min-w-sm flex flex-col rounded-lg bg-page text-center">
<ModalHeader currentStep={currentStepConfig} />
<Modal.Banner
currentStep={currentStepConfig}
icon={Server01Icon}
name="New Cluster"
/>

<div className="flex flex-col rounded-b-lg border border-white/5">
<div className="p-3">
{stepContent}
</div>

<ModalFooter
<Modal.Footer
isFirstStep={isFirstStep}
isNextDisabled={isNextDisabled}
nextButtonText={nextButtonText}
Expand All @@ -192,68 +195,6 @@ export function NewClusterCreate() {
);
}

interface ModalHeaderProps {
currentStep: typeof STEPS[number];
}

function ModalHeader({ currentStep }: ModalHeaderProps) {
return (
<div className="theme-OneLauncher-Dark relative h-25 flex">
<div className="absolute left-0 top-0 h-full w-full">
<img
alt="Header Image"
className="h-full w-full rounded-t-lg"
src={DefaultBanner}
/>
</div>
<div className="absolute left-0 top-0 h-full flex w-full flex-row items-center justify-start gap-x-4 bg-[radial-gradient(at_center,#00000077,transparent)] px-10">
<Server01Icon className="h-8 w-8 text-fg-primary" />
<div className="flex flex-col items-start justify-center">
<h1 className="h-10 text-fg-primary text-2xl font-semibold">New Cluster</h1>
<span className="text-fg-primary">{currentStep.title}</span>
</div>
</div>
</div>
);
}

interface ModalFooterProps {
isFirstStep: boolean;
isNextDisabled: boolean;
nextButtonText: string;
onBack: () => void;
onNext: () => void;
}

function ModalFooter({
isFirstStep,
isNextDisabled,
nextButtonText,
onBack,
onNext,
}: ModalFooterProps) {
return (
<div className="flex flex-row justify-end gap-x-2 p-3 pt-0">
<Button
color="ghost"
isDisabled={isFirstStep}
onClick={onBack}
>
Previous
</Button>
<Button
color="primary"
isDisabled={isNextDisabled}
onClick={onNext}
>
{nextButtonText}
{' '}
<ArrowRightIcon />
</Button>
</div>
);
}

interface ClusterLoaderProps {
selectedProvider: string;
onSelectProvider: (provider: string) => void;
Expand Down
87 changes: 85 additions & 2 deletions apps/onelauncher/frontend/src/components/overlay/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { ComponentType, SVGProps } from 'react';
import type { DialogProps } from 'react-aria-components';
import type { VariantProps } from 'tailwind-variants';
import DefaultBanner from '@/assets/images/default_banner.png';
import { Button } from '@onelauncher/common/components';
import { ArrowRightIcon } from '@untitled-theme/icons-react';
import { createElement } from 'react';
import {
Dialog as AriaDialog,
Modal as AriaModal,
Expand Down Expand Up @@ -37,7 +42,7 @@ export interface ModalProps extends DialogProps, VariantProps<typeof modalVarian
modalClassName?: string;
}

function Modal({
export default function Modal({
className,
isOpen,
onOpenChange,
Expand Down Expand Up @@ -70,4 +75,82 @@ function Modal({

Modal.Trigger = DialogTrigger;

export default Modal;
export interface ModalBannerProps {
name: string;
icon?: ComponentType<SVGProps<SVGSVGElement>>;
banner?: string;
currentStep?: {
id: string;
title: string;
};
}

Modal.Banner = ({ name, banner, icon, currentStep }: ModalBannerProps) => (
<div className="theme-OneLauncher-Dark relative h-25 flex">
<div className="absolute left-0 top-0 h-full w-full">
<img
alt="Header Image"
className="h-full w-full rounded-t-lg"
src={banner ?? DefaultBanner}
/>
</div>
<div className="absolute left-0 top-0 h-full flex w-full flex-row items-center justify-start gap-x-4 bg-[radial-gradient(at_center,#00000077,transparent)] px-10">
{icon && createElement(icon, { className: 'h-8 w-8 text-fg-primary' })}
<div className="flex flex-col items-start justify-center">
<h1 className="h-10 text-fg-primary text-2xl font-semibold">{name}</h1>
{currentStep ? <span className="text-fg-primary">{currentStep.title}</span> : null}
</div>
</div>
</div>
);

export interface ModalHeaderProps {
name: string;
fontsize?: string;
currentStep?: {
id: string;
title: string;
};
}

Modal.Header = ({ name, fontsize, currentStep }: ModalHeaderProps) => (
<div className="theme-OneLauncher-Dark relative items-center flex justify-start px-4 bg-[radial-gradient(at_center,#00000077,transparent)] pt-2 h-auto">
<h1 className={`text-fg-primary ${fontsize ?? 'text-xl'} font-semibold`}>{name}</h1>
{currentStep ? <span className="text-fg-primary">{currentStep.title}</span> : null}
</div>
);

export interface ModalFooterProps {
isFirstStep: boolean;
isNextDisabled: boolean;
nextButtonText: string;
onBack: () => void;
onNext: () => void;
}

Modal.Footer = ({
isFirstStep,
isNextDisabled,
nextButtonText,
onBack,
onNext,
}: ModalFooterProps) => (
<div className="flex flex-row justify-end gap-x-2 p-3 pt-0">
<Button
color="ghost"
isDisabled={isFirstStep}
onClick={onBack}
>
Previous
</Button>
<Button
color="primary"
isDisabled={isNextDisabled}
onClick={onNext}
>
{nextButtonText}
{' '}
<ArrowRightIcon />
</Button>
</div>
);
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import type { MinecraftCredentials } from '@/bindings.gen';
import PlayerHead from '@/components/content/PlayerHead';
import { bindings } from '@/main';
import { useCommand } from '@onelauncher/common';
import { Button } from '@onelauncher/common/components';
import { Button, ContextMenu } from '@onelauncher/common/components';
import { Link } from '@tanstack/react-router';
import { PlusIcon, Settings01Icon } from '@untitled-theme/icons-react';
import { useRef, useState } from 'react';
import { twMerge } from 'tailwind-merge';

function AccountPopup() {
Expand Down Expand Up @@ -71,10 +72,23 @@ function AccountEntry({
user: MinecraftCredentials;
loggedIn?: boolean;
}) {
const ref = useRef<HTMLDivElement>(null);
const [isOpen, setOpen] = useState(false);

const removeUserCommand = useCommand(
'removeUser',
() => bindings.core.removeUser(user.id),
{
enabled: false,
subscribed: false,
},
);

return (
<div
className={twMerge('flex flex-row justify-between p-2 rounded-lg', !loggedIn && 'hover:bg-component-bg-hover active:bg-component-bg-pressed hover:text-fg-primary-hover')}
onClick={onClick}
ref={ref}
>
<div className="flex flex-1 flex-row justify-start gap-x-3">
<PlayerHead className="h-8 w-8 rounded-md" uuid={user.id} />
Expand All @@ -85,6 +99,16 @@ function AccountEntry({
</div>
</div>
</div>

<ContextMenu
isOpen={isOpen}
setOpen={setOpen}
triggerRef={ref}
>
<ContextMenu.Item className="text-red-500 rounded-sm px-3 py-1 hover:bg-component-bg-hover" onAction={removeUserCommand.refetch}>
Delete
</ContextMenu.Item>
</ContextMenu>
</div>
);
}
Loading
Loading