feat: Close confirmation dialog

This commit is contained in:
LynithDev 2024-03-15 22:06:36 +01:00
parent 6fdea8c033
commit b2226a07e7
9 changed files with 156 additions and 34 deletions

View file

@ -30,6 +30,7 @@
"eslint-plugin-solid": "^0.13.1",
"postcss": "^8.4.35",
"postcss-easings": "^4.0.0",
"sass": "^1.72.0",
"tailwindcss": "^3.4.1",
"typescript": "^5.0.2",
"vite": "^5.0.0",

26
pnpm-lock.yaml generated
View file

@ -55,6 +55,9 @@ devDependencies:
postcss-easings:
specifier: ^4.0.0
version: 4.0.0(postcss@8.4.35)
sass:
specifier: ^1.72.0
version: 1.72.0
tailwindcss:
specifier: ^3.4.1
version: 3.4.1
@ -63,7 +66,7 @@ devDependencies:
version: 5.4.2
vite:
specifier: ^5.0.0
version: 5.1.6
version: 5.1.6(sass@1.72.0)
vite-plugin-solid:
specifier: ^2.8.0
version: 2.10.1(solid-js@1.8.15)(vite@5.1.6)
@ -2374,6 +2377,10 @@ packages:
engines: {node: '>= 4'}
dev: true
/immutable@4.3.5:
resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==}
dev: true
/import-fresh@3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
@ -3127,6 +3134,16 @@ packages:
is-regex: 1.1.4
dev: true
/sass@1.72.0:
resolution: {integrity: sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA==}
engines: {node: '>=14.0.0'}
hasBin: true
dependencies:
chokidar: 3.6.0
immutable: 4.3.5
source-map-js: 1.0.2
dev: true
/semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
@ -3555,13 +3572,13 @@ packages:
merge-anything: 5.1.7
solid-js: 1.8.15
solid-refresh: 0.6.3(solid-js@1.8.15)
vite: 5.1.6
vite: 5.1.6(sass@1.72.0)
vitefu: 0.2.5(vite@5.1.6)
transitivePeerDependencies:
- supports-color
dev: true
/vite@5.1.6:
/vite@5.1.6(sass@1.72.0):
resolution: {integrity: sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
@ -3592,6 +3609,7 @@ packages:
esbuild: 0.19.12
postcss: 8.4.35
rollup: 4.13.0
sass: 1.72.0
optionalDependencies:
fsevents: 2.3.3
dev: true
@ -3604,7 +3622,7 @@ packages:
vite:
optional: true
dependencies:
vite: 5.1.6
vite: 5.1.6(sass@1.72.0)
dev: true
/which-boxed-primitive@1.0.2:

View file

@ -2,7 +2,15 @@
@tailwind components;
@tailwind utilities;
body {
@apply text-gray-400 text-md;
}
/* start lynith's native experience */
* { user-select: none; }
*:hover { cursor: default; }
/* end lynith's native experience */
/* end lynith's native experience */
h1 { @apply text-2xl font-bold; }
h2 { @apply text-xxl font-bold; }
h3 { @apply text-xl font-bold; }

View file

@ -3,7 +3,7 @@ import WindowFrame from './components/native/WindowFrame';
function App(props: ParentProps) {
return (
<main class='bg-bg-primary min-h-screen text-white'>
<main class='bg-primary min-h-screen text-white'>
<WindowFrame />
{props.children}
</main>

View file

@ -0,0 +1,16 @@
.button {
@apply border border-white/5
bg-component-bg hover:bg-component-bg-hover active:bg-component-bg-pressed;
&.size--sm {
}
&.size-md {
@apply py-2 px-4 rounded-lg;
}
&.size-lg {
}
}

View file

@ -0,0 +1,19 @@
import { JSX, ParentProps, mergeProps } from 'solid-js';
import styles from './Button.module.scss';
type ButtonProps = JSX.ButtonHTMLAttributes<HTMLButtonElement> & ParentProps & {
size?: 'sm' | 'md' | 'lg',
style?: 'primary' | 'secondary' | 'danger', // TODO
};
function Button(props: ButtonProps) {
const merged = mergeProps({ size: 'md' }, props);
return (
<button class={`${styles.button} ${styles[`size-${merged.size}`]}`} {...props}>
{props.children}
</button>
);
}
export default Button;

View file

@ -2,18 +2,19 @@ import { Window } from '@tauri-apps/api/window';
import { MinusIcon, XCloseIcon } from '@untitled-theme/icons-solid';
import { JSX, createSignal } from 'solid-js';
import Modal from '../overlay/Modal';
import Button from '../base/Button';
type ButtonProps = {
type TitlebarButtonProps = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
icon: (any: any) => JSX.Element,
onClick: (event: MouseEvent) => void,
danger?: boolean,
};
function Button(props: ButtonProps) {
function TitlebarButton(props: TitlebarButtonProps) {
return (
<button class='flex items-center justify-center w-8 h-8 group' onClick={(e) => props.onClick(e)}>
<div class='rounded-lg group-hover:bg-bg-primary p-1'>
<div class='rounded-lg group-hover:bg-primary p-1'>
<props.icon class={`w-[18px] h-[18px] stroke-slate ${props.danger ? 'group-hover:stroke-danger' : 'group-hover:stroke-white'}`} />
</div>
</button>
@ -21,16 +22,25 @@ function Button(props: ButtonProps) {
}
function WindowFrame() {
const [isCloseModalVisible, setIsCloseModalVisible] = createSignal(false);
const [isModalVisible, setModalVisible] = createSignal(false);
const minimize = () => Window.getCurrent().minimize();
const quit = () => Window.getCurrent().close();
return (
<div data-tauri-drag-region class="flex flex-row gap-2 justify-end items-center w-screen h-8 bg-bg-secondary pr-4">
<Button icon={MinusIcon} onClick={() => Window.getCurrent().minimize()} />
<Button icon={XCloseIcon} onClick={() => {
setIsCloseModalVisible(!isCloseModalVisible());
}} danger />
<div data-tauri-drag-region class="flex flex-row gap-2 justify-end items-center w-screen h-8 bg-secondary pr-4">
<TitlebarButton icon={MinusIcon} onClick={() => minimize()} />
<TitlebarButton icon={XCloseIcon} onClick={() => setModalVisible(true)} danger />
<Modal title='Close' visible={isCloseModalVisible} setVisible={setIsCloseModalVisible} />
<Modal
title='Close OneLauncher?'
visible={isModalVisible}
setVisible={setModalVisible}
buttons={[
<Button onClick={() => setModalVisible(false)}>No</Button>,
<Button onClick={() => quit()}>Yes</Button>,
]}
/>
</div>
);
}

View file

@ -1,42 +1,71 @@
import {
Accessor,
ParentProps, Setter, Show, createEffect, createSignal,
ParentProps, Setter, Show, createEffect, createSignal, For,
mergeProps,
JSX,
} from 'solid-js';
import { Portal } from 'solid-js/web';
import Button from '../base/Button';
type ModalButton = {
text: string,
class?: string,
onClick?: (event: MouseEvent) => void,
};
type ModalButtonProps = string | JSX.Element;
function ModalButton(button: { props: ModalButtonProps }) {
return <>
{typeof button.props === 'string' ? (
<Button>
{button.props}
</Button>
) : (
button.props
)}
</>;
}
type ModalProps = {
title: string,
visible: Accessor<boolean>,
setVisible: Setter<boolean>,
buttons?: ModalButton[],
buttons?: ModalButtonProps[],
} & ParentProps;
function Modal(props: ModalProps) {
const [localVisible, setLocalVisible] = createSignal(false);
const [animate, setAnimate] = createSignal('animate-fade-in');
const merged: ModalProps = mergeProps({ buttons: ['Ok'] }, props);
createEffect(() => {
if (props.visible()) {
setAnimate('animate-fade-in');
setLocalVisible(true);
} else {
setAnimate('animate-fade-out');
setTimeout(() => {
setLocalVisible(false);
}, 150);
}
});
function onBackdropClick() {
setAnimate('animate-fade-out pointer-events-none');
setTimeout(() => {
props.setVisible(false);
setAnimate('animate-fade-in pointer-events-auto');
}, 150);
props.setVisible(false);
}
return (
<Show when={props.visible()}>
<Show when={localVisible()}>
<Portal>
<div class={`fixed z-[1000] top-0 left-0 w-screen h-screen bg-black/50 backdrop-blur-md ${animate()}`}>
<div class='absolute w-full h-full' onClick={() => onBackdropClick()} />
<div class='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
<div class='bg-white p-4'>
<h1>Hello World</h1>
<div class='bg-primary border border-white/5 p-4 rounded-lg text-center flex flex-col gap-y-1'>
<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>

View file

@ -2,15 +2,36 @@
export default {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
fontSize: {
// Based off 16px
sm: '0.688rem',
md: '0.875rem',
lg: '1rem',
xl: '1.25rem',
xxl: '1.5rem',
'2xl': '2rem',
},
colors: {
white: '#ffffff',
black: '#000000',
slate: '#9BA1A6',
danger: '#E5484D',
bg: {
primary: '#11171C',
secondary: '#192026',
gray: {
400: '#D5DBFF',
},
component: {
bg: {
DEFAULT: '#1A2229',
hover: '#171F25',
pressed: '#222C35',
},
},
primary: '#11171C',
secondary: '#192026',
},
extend: {
animation: {