feat: begin work on Cluster creation modal
This commit is contained in:
parent
060f1faa10
commit
9c7b895d4c
7 changed files with 189 additions and 77 deletions
|
|
@ -6,6 +6,7 @@ import ErrorBoundary from './components/ErrorBoundary';
|
|||
import AnimatedRoutes from './components/AnimatedRoutes';
|
||||
import NotificationOverlay from './components/overlay/notifications/NotificationOverlay';
|
||||
import { SettingsProvider } from './hooks/useSettings';
|
||||
import { ClusterModalController } from './components/overlay/cluster/ClusterCreationModal';
|
||||
import { AppInfo } from '~utils/program-info';
|
||||
|
||||
function App(props: ParentProps) {
|
||||
|
|
@ -15,28 +16,30 @@ function App(props: ParentProps) {
|
|||
});
|
||||
|
||||
return (
|
||||
<SettingsProvider>
|
||||
<main class="flex flex-col bg-primary w-full min-h-screen overflow-hidden h-screen max-h-screen text-fg-primary">
|
||||
<WindowFrame />
|
||||
<div class="flex flex-col px-8">
|
||||
<Navbar />
|
||||
</div>
|
||||
|
||||
<div class="relative h-full w-full overflow-hidden">
|
||||
<div class="absolute top-0 left-0 flex flex-col h-full w-full overflow-x-hidden">
|
||||
<ErrorBoundary>
|
||||
<OverlayScrollbarsComponent class="os-hide-horizontal-scrollbar absolute top-0 left-0 flex flex-col h-full w-full overflow-x-hidden overflow-y-auto px-8 pb-8">
|
||||
<AnimatedRoutes>
|
||||
{props.children}
|
||||
</AnimatedRoutes>
|
||||
</OverlayScrollbarsComponent>
|
||||
</ErrorBoundary>
|
||||
<ClusterModalController>
|
||||
<SettingsProvider>
|
||||
<main class="flex flex-col bg-primary w-full min-h-screen overflow-hidden h-screen max-h-screen text-fg-primary">
|
||||
<WindowFrame />
|
||||
<div class="flex flex-col px-8">
|
||||
<Navbar />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NotificationOverlay />
|
||||
</main>
|
||||
</SettingsProvider>
|
||||
<div class="relative h-full w-full overflow-hidden">
|
||||
<div class="absolute top-0 left-0 flex flex-col h-full w-full overflow-x-hidden">
|
||||
<ErrorBoundary>
|
||||
<OverlayScrollbarsComponent class="os-hide-horizontal-scrollbar absolute top-0 left-0 flex flex-col h-full w-full overflow-x-hidden overflow-y-auto px-8 pb-8">
|
||||
<AnimatedRoutes>
|
||||
{props.children}
|
||||
</AnimatedRoutes>
|
||||
</OverlayScrollbarsComponent>
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NotificationOverlay />
|
||||
</main>
|
||||
</SettingsProvider>
|
||||
</ClusterModalController>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ function WindowFrame() {
|
|||
<TitlebarButton icon={XCloseIcon} onClick={() => quit()} danger />
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
<Modal.Simple
|
||||
title="Close OneLauncher?"
|
||||
visible={isModalVisible}
|
||||
setVisible={setModalVisible}
|
||||
|
|
|
|||
|
|
@ -8,19 +8,27 @@ import { Portal } from 'solid-js/web';
|
|||
type FullscreenOverlayProps = {
|
||||
visible: Accessor<boolean>;
|
||||
setVisible: Setter<boolean>;
|
||||
mount?: Node | undefined;
|
||||
zIndex?: number;
|
||||
} & ParentProps;
|
||||
|
||||
function FullscreenOverlay(props: FullscreenOverlayProps) {
|
||||
function onBackdropClick() {
|
||||
props.setVisible(false);
|
||||
function onBackdropClick(this: HTMLDivElement, e: MouseEvent) {
|
||||
e.preventDefault();
|
||||
if (e.target === this)
|
||||
props.setVisible(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<div class={`fixed z-[1000] top-0 left-0 w-screen h-screen bg-black/60 backdrop-blur-sm backdrop-grayscale transition-opacity ${props.visible() ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'}`}>
|
||||
<div class="absolute w-full h-full" onClick={() => onBackdropClick()} />
|
||||
<Portal {...(props.mount ? { mount: props.mount } : {})}>
|
||||
<div
|
||||
style={{ 'z-index': props.zIndex || 1000 }}
|
||||
class={`fixed top-0 left-0 w-screen h-screen bg-black/60 backdrop-blur-sm backdrop-grayscale transition-opacity ${props.visible() ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'}`}
|
||||
>
|
||||
{/* New element to prevent from having to call stopPropagation in child elements */}
|
||||
{/* <div class="absolute w-full h-full" onClick={() => onBackdropClick()} /> */}
|
||||
|
||||
<div class="absolute top-0 left-0 w-screen h-screen">
|
||||
<div class="absolute top-0 left-0 w-screen h-screen" onClick={onBackdropClick}>
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,71 @@ import type {
|
|||
Accessor,
|
||||
JSX,
|
||||
ParentProps,
|
||||
Ref,
|
||||
Setter,
|
||||
} from 'solid-js';
|
||||
import { For, mergeProps } from 'solid-js';
|
||||
import { For } from 'solid-js';
|
||||
import { mergeRefs } from '@solid-primitives/refs';
|
||||
import Button from '../base/Button';
|
||||
import FullscreenOverlay from './FullscreenOverlay';
|
||||
|
||||
export type ModalProps = {
|
||||
visible: Accessor<boolean>;
|
||||
setVisible: Setter<boolean>;
|
||||
zIndex?: number | undefined;
|
||||
mount?: Node | undefined;
|
||||
ref?: Ref<HTMLDivElement> | undefined;
|
||||
} & ParentProps;
|
||||
|
||||
// TODO: Implement some sort of stacking control?
|
||||
function Modal(props: ModalProps) {
|
||||
return (
|
||||
<FullscreenOverlay
|
||||
visible={props.visible}
|
||||
setVisible={props.setVisible}
|
||||
mount={props.mount}
|
||||
zIndex={props.zIndex || 1000}
|
||||
>
|
||||
<div ref={mergeRefs(props.ref)} class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<div class="bg-primary border border-white/5 p-4 rounded-lg text-center flex flex-col gap-y-2 min-w-xs">
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
</FullscreenOverlay>
|
||||
);
|
||||
}
|
||||
|
||||
type ModalButtonProps = string | JSX.Element;
|
||||
|
||||
export type ModalSimpleProps = {
|
||||
title: string;
|
||||
buttons?: ModalButtonProps[];
|
||||
} & ModalProps;
|
||||
|
||||
Modal.Simple = function (props: ModalSimpleProps) {
|
||||
return (
|
||||
<Modal
|
||||
ref={props.ref}
|
||||
setVisible={props.setVisible}
|
||||
visible={props.visible}
|
||||
mount={props.mount}
|
||||
zIndex={props.zIndex}
|
||||
>
|
||||
<h2>{props.title}</h2>
|
||||
<div class="flex flex-col">
|
||||
{props.children}
|
||||
</div>
|
||||
<div class="flex flex-row gap-x-4 [&>*]:flex-1">
|
||||
<For each={props.buttons}>
|
||||
{button => (
|
||||
<ModalButton props={button} />
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
function ModalButton(button: { props: ModalButtonProps }) {
|
||||
return (
|
||||
<>
|
||||
|
|
@ -26,38 +83,4 @@ function ModalButton(button: { props: ModalButtonProps }) {
|
|||
);
|
||||
}
|
||||
|
||||
type ModalProps = {
|
||||
title: string;
|
||||
visible: Accessor<boolean>;
|
||||
setVisible: Setter<boolean>;
|
||||
buttons?: ModalButtonProps[];
|
||||
} & ParentProps;
|
||||
|
||||
function Modal(props: ModalProps) {
|
||||
const merged: ModalProps = mergeProps({ buttons: ['Ok'] }, props);
|
||||
|
||||
return (
|
||||
<FullscreenOverlay
|
||||
visible={props.visible}
|
||||
setVisible={props.setVisible}
|
||||
>
|
||||
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<div class="bg-primary border border-white/5 p-4 rounded-lg text-center flex flex-col gap-y-2 min-w-xs">
|
||||
<h2>{props.title}</h2>
|
||||
<div class="flex flex-col">
|
||||
{props.children}
|
||||
</div>
|
||||
<div class="flex flex-row gap-x-4 [&>*]:flex-1">
|
||||
<For each={merged.buttons}>
|
||||
{button => (
|
||||
<ModalButton props={button} />
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FullscreenOverlay>
|
||||
);
|
||||
}
|
||||
|
||||
export default Modal;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
import { type Accessor, type Context, Match, type ParentProps, type Setter, Show, Switch, createContext, createSignal, useContext } from 'solid-js';
|
||||
import { Server01Icon } from '@untitled-theme/icons-solid';
|
||||
import Modal, { type ModalProps } from '../Modal';
|
||||
import HeaderImage from '../../../../assets/images/header.png';
|
||||
|
||||
// Why the fuck do I need to use a context for all this???
|
||||
// TODO: Rewrite for use with the new Modal stacking system
|
||||
type ClusterModalContextFunc = [
|
||||
step: Accessor<number>,
|
||||
setStep: Setter<number>,
|
||||
setVisible: Setter<boolean>,
|
||||
];
|
||||
|
||||
const ClusterModalContext = createContext<ClusterModalContextFunc>() as Context<ClusterModalContextFunc>;
|
||||
|
||||
export function ClusterModalController(props: ParentProps) {
|
||||
const [step, setStep] = createSignal(1);
|
||||
const [visible, setVisible] = createSignal(false);
|
||||
|
||||
const stepper: ClusterModalContextFunc = [
|
||||
step,
|
||||
setStep,
|
||||
setVisible,
|
||||
];
|
||||
|
||||
return (
|
||||
<ClusterModalContext.Provider value={stepper}>
|
||||
{props.children}
|
||||
<ClusterCreationModal visible={visible} setVisible={setVisible} step={step()} />
|
||||
</ClusterModalContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useClusterModalController() {
|
||||
return useContext(ClusterModalContext);
|
||||
}
|
||||
|
||||
type ClusterCreationModalProps = ModalProps & {
|
||||
step: number;
|
||||
};
|
||||
|
||||
function ClusterCreationModal(props: ClusterCreationModalProps) {
|
||||
// const StepComponent = () => (
|
||||
// <Switch>
|
||||
// <Match when={step() === 1}>
|
||||
// <ClusterStepOne />
|
||||
// </Match>
|
||||
// </Switch>
|
||||
// );
|
||||
|
||||
return (
|
||||
<Modal {...props}>
|
||||
<div class="relative h-22">
|
||||
<div class="absolute top-0 left-0 w-full">
|
||||
<img src={HeaderImage} alt="Header Image" />
|
||||
</div>
|
||||
<div class="absolute top-0 left-0 w-full flex flex-row justify-center items-center gap-x-2">
|
||||
<Server01Icon />
|
||||
<div class="flex flex-col">
|
||||
<h1>New Cluster</h1>
|
||||
<span>agagwag</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import type { JSX } from 'solid-js';
|
||||
|
||||
export default function ClusterStepOne() {
|
||||
return (
|
||||
<div class="grid grid-cols-3">
|
||||
helo
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface ProviderCardProps {
|
||||
icon: () => JSX.Element;
|
||||
name: string;
|
||||
};
|
||||
|
||||
function ProviderCard(props: ProviderCardProps) {
|
||||
return (
|
||||
<div class="flex flex-col justify-center items-center gap-y-2">
|
||||
<props.icon />
|
||||
<span>{props.name}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ import type { Cluster } from '~bindings';
|
|||
import useCommand from '~ui/hooks/useCommand';
|
||||
import { bridge } from '~imports';
|
||||
import { upperFirst } from '~utils/primitives';
|
||||
import { useClusterModalController } from '~ui/components/overlay/cluster/ClusterCreationModal';
|
||||
|
||||
// TODO: Replace this into it's own component
|
||||
// possibly with the core ui lirbary with autogenerated and optimized svgs pls
|
||||
|
|
@ -186,23 +187,10 @@ function ClusterGroup(props: ClusterGroupProps) {
|
|||
|
||||
function HomePage() {
|
||||
const [clusters, { refetch }] = useCommand(bridge.commands.getClusters);
|
||||
const [step, setStep, setVisible] = useClusterModalController();
|
||||
|
||||
async function newInstance() {
|
||||
// bridge.commands.createCluster({
|
||||
|
||||
// });
|
||||
|
||||
// await createCluster({
|
||||
// name: '1.0 cluster',
|
||||
// version: 'a1.0.11',
|
||||
// client: {
|
||||
// type: 'Vanilla',
|
||||
// },
|
||||
// cover: null,
|
||||
// group: null,
|
||||
// });
|
||||
|
||||
// await refetch();
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue