diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 2bd7cd80..884c3603 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -19,6 +19,7 @@ module.exports = { '@typescript-eslint/indent': 'off', '@stylistic/ts/indent': ['error', 4], '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/no-namespace': 'off', 'import/extensions': [ 'error', { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 1ff6798d..fb95bf10 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -4,12 +4,13 @@ use std::error::Error; use polyfrost_launcher::auth; -use tauri::App; +use tauri::{menu::Menu, App}; fn main() { tauri::Builder::default() .plugin(tauri_plugin_shell::init()) .plugin(auth::init()) + .menu(|handle| Menu::new(handle)) .setup(setup) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/globals.css b/src/globals.css index 27ec0579..b2a63d25 100644 --- a/src/globals.css +++ b/src/globals.css @@ -9,8 +9,22 @@ body { /* start lynith's native experience */ * { user-select: none; cursor: default !important; } *:hover { cursor: default !important; } +img { -webkit-user-drag: none; } /* end lynith's native experience */ h1 { @apply text-2xl font-semibold; } h2 { @apply text-xxl font-semibold; } h3 { @apply text-xl font-medium; } + +.slide-fade-enter-active, +.slide-fade-exit-active { + transition: opacity 0.3s, transform 0.3s; +} +.slide-fade-enter, +.slide-fade-exit-to { + transform: translateX(10px); + opacity: 0; +} +.slide-fade-enter { + transform: translateX(-10px); +} diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 6bdd6617..9d4410de 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -2,13 +2,20 @@ import { ParentProps } from 'solid-js'; import { Transition } from 'solid-transition-group'; import WindowFrame from './components/native/WindowFrame'; import Navbar from './components/Navbar'; +import environment from '../utils/environment'; function App(props: ParentProps) { + if (!environment.isDev()) { + document.addEventListener('contextmenu', (event) => { + event.preventDefault(); + }); + } + return (
- -
+
+ { /* eslint-disable-next-line @typescript-eslint/no-use-before-define */ } {props.children} diff --git a/src/ui/components/Navbar.tsx b/src/ui/components/Navbar.tsx index 4d9a0d1a..b8970c72 100644 --- a/src/ui/components/Navbar.tsx +++ b/src/ui/components/Navbar.tsx @@ -1,11 +1,14 @@ import { A } from '@solidjs/router'; +import { ParentProps, createSignal } from 'solid-js'; +import PolyfrostFull from './logos/PolyfrostFull'; +import AccountPopup from './overlay/AccountPopup'; -type NavbarButtonProps = { +type NavbarLinkProps = { path: string, label: string, }; -function NavbarButton(props: NavbarButtonProps) { +function NavbarLink(props: NavbarLinkProps) { return ( -
- - - +
+
+
+
+ + + +
+
+ +
+ +
); } diff --git a/src/ui/components/base/Button.module.scss b/src/ui/components/base/Button.module.scss index e2d1367c..77cdf6ef 100644 --- a/src/ui/components/base/Button.module.scss +++ b/src/ui/components/base/Button.module.scss @@ -1,5 +1,5 @@ .button { - @apply py-1.5 px-4 rounded-lg flex flex-row justify-center items-center gap-x-2.5; + @apply py-1.5 px-3 rounded-lg flex flex-row justify-center items-center gap-x-2.5; &__primary { @apply text-onbrand hover:text-onbrand-hover active:text-onbrand-pressed disabled:text-onbrand-disabled; @@ -15,6 +15,18 @@ &__danger { @apply bg-danger hover:bg-danger-hover active:bg-danger-pressed disabled:bg-danger-disabled; } + + &__ghost { + @apply hover:bg-gray-.5 active:bg-gray-.10; + } + + &__icon { + @apply p-1.5 hover:bg-gray-.5 active:bg-gray-.10 aspect-square box-border; + + & > * { + @apply w-full h-full; + } + } } .icon > * { diff --git a/src/ui/components/base/Button.tsx b/src/ui/components/base/Button.tsx index 92b39203..ec806550 100644 --- a/src/ui/components/base/Button.tsx +++ b/src/ui/components/base/Button.tsx @@ -6,7 +6,7 @@ import styles from './Button.module.scss'; type ButtonProps = JSX.ButtonHTMLAttributes & ParentProps & { iconLeft?: JSX.Element, iconRight?: JSX.Element, - styleType?: 'primary' | 'secondary' | 'danger', + styleType?: 'primary' | 'secondary' | 'danger' | 'icon' | 'ghost', }; function Button(props: ButtonProps) { @@ -14,7 +14,7 @@ function Button(props: ButtonProps) { const merged = mergeProps({ styleType: 'primary' }, buttonProps); return ( - + )} +
+ ); +} + +function AccountPopup(props: Popup.PopupProps) { + return ( + +
+
+ + +
+ + + + + +
+ +
+
+ +
+
+ +
+
+ +
+
+ + ); +} + +export default AccountPopup; diff --git a/src/ui/components/overlay/Popup.tsx b/src/ui/components/overlay/Popup.tsx new file mode 100644 index 00000000..e2a80441 --- /dev/null +++ b/src/ui/components/overlay/Popup.tsx @@ -0,0 +1,59 @@ +import { + Accessor, + createEffect, createSignal, + ParentProps, + Setter, + Show, +} from 'solid-js'; +import { Portal } from 'solid-js/web'; + +declare namespace Popup { + interface PopupProps extends ParentProps { + visible: Accessor, + setVisible: Setter, + class?: string, + mount?: Node, + } +} + +function Popup(props: Popup.PopupProps) { + const [localVisible, setLocalVisible] = createSignal(false); + const [animate, setAnimate] = createSignal('animate-fade-in'); + + let popupRef!: HTMLDivElement; + + function onClick(e: MouseEvent) { + if (!popupRef || !localVisible()) return; + + const clicked = e.target === popupRef || popupRef.contains(e.target as Node); + if (!clicked) { + props.setVisible(false); + } + } + + createEffect(() => { + if (props.visible()) { + document.addEventListener('click', onClick); + setAnimate('animate-fade-in'); + setLocalVisible(true); + } else { + document.removeEventListener('click', onClick); + setAnimate('animate-fade-out'); + setTimeout(() => { + setLocalVisible(false); + }, 150); + } + }); + + return ( + + +
+ {props.children} +
+
+
+ ); +} + +export default Popup; diff --git a/src/ui/pages/Home.tsx b/src/ui/pages/Home.tsx index 6e0b92b9..07dd1859 100644 --- a/src/ui/pages/Home.tsx +++ b/src/ui/pages/Home.tsx @@ -35,9 +35,9 @@ function Banner() {
- +
} /> diff --git a/src/utils/environment.ts b/src/utils/environment.ts new file mode 100644 index 00000000..91f49ff8 --- /dev/null +++ b/src/utils/environment.ts @@ -0,0 +1,7 @@ +function isDev() { + return window.location.host.startsWith('localhost:'); +} + +export default { + isDev, +};