Skip to content

Commit

Permalink
Merge pull request #88 from Team-BTMC/feature/sidebar
Browse files Browse the repository at this point in the history
New UI 2
  • Loading branch information
duduBTW authored Nov 19, 2024
2 parents 16f562a + 652f076 commit 338033e
Show file tree
Hide file tree
Showing 67 changed files with 2,061 additions and 885 deletions.
1 change: 1 addition & 0 deletions src/@types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export type System = {
// Settings table definition
export type Settings = {
volume: number;
sidebarWidth: number;
audioDeviceId: string;
osuSongsDir: string;
"window.width": number;
Expand Down
3 changes: 2 additions & 1 deletion src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ async function createWindow() {
show: false,
autoHideMenuBar: true,
titleBarStyle: "hidden",
minWidth: 500,
trafficLightPosition: {
x: 20,
y: 20,
y: 28,
},
icon: getIcon(),
webPreferences: {
Expand Down
49 changes: 33 additions & 16 deletions src/renderer/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { Scenes } from "../../@types";
import NoticeContainer from "./components/notice/NoticeContainer";
import Popover from "./components/popover/Popover";
import "./keyboard-registers/initialize";
import { fetchOs, os, setOs } from "./lib/os";
import { TokenNamespace } from "./lib/tungsten/token";
import ErrorScene from "./scenes/ErrorScene";
import NoScene from "./scenes/NoScene";
import DirSelectScene from "./scenes/dir-select-scene/DirSelectScene";
import LoadingScene from "./scenes/loading-scene/LoadingScene";
import MainScene from "./scenes/main-scene/MainScene";
import type { JSX } from "solid-js";
import { createSignal, Match, onCleanup, onMount, Switch } from "solid-js";
import { createMemo, createSignal, Match, onCleanup, onMount, Show, Switch } from "solid-js";
import { sidebarWidth } from "./scenes/main-scene/main.utils";

export default function App(): JSX.Element {
const [scene, setScene] = createSignal<Scenes>("");
Expand All @@ -22,31 +26,44 @@ export default function App(): JSX.Element {
setScene(event.detail.scene);
};

onMount(() => {
onMount(async () => {
window.api.listen("changeScene", setScene);
window.addEventListener("changeScene", eventHandler);

// Sets current OS
setOs(await fetchOs());
});

onCleanup(() => {
window.api.removeListener("changeScene", setScene);
window.removeEventListener("changeScene", eventHandler);
});

const hasRequiredOptions = createMemo(() => {
return typeof os() !== "undefined" && typeof sidebarWidth() !== "undefined";
});

return (
<Switch fallback={<NoScene />}>
<Match when={scene() === "dir-select"}>
<DirSelectScene />
</Match>
<Match when={scene() === "main"}>
<MainScene />
</Match>
<Match when={scene() === "loading"}>
<LoadingScene />
</Match>
<Match when={scene() === "error"}>
<ErrorScene />
</Match>
</Switch>
<Show when={hasRequiredOptions()}>
<NoticeContainer />

<Switch fallback={<NoScene />}>
<Match when={scene() === "dir-select"}>
<DirSelectScene />
</Match>
<Match when={scene() === "main"}>
<MainScene />
</Match>
<Match when={scene() === "loading"}>
<LoadingScene />
</Match>
<Match when={scene() === "error"}>
<ErrorScene />
</Match>
</Switch>

<Popover.PortalMountStack />
</Show>
);
}

Expand Down
6 changes: 5 additions & 1 deletion src/renderer/src/components/InfiniteScroller.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,11 @@ const InfiniteScroller: Component<InfinityScrollerProps> = (props) => {
});

return (
<div class={"list flex flex-col gap-4 py-4"} ref={container} {...rest}>
<div
class="grid grid-cols-[repeat(auto-fit,_minmax(340px,_1fr))] gap-4 py-4 items-stretch"
ref={container}
{...rest}
>
<Show when={show() === true} fallback={props.fallback ?? <div>No items...</div>}>
<For each={elements()}>{(componentProps) => props.builder(componentProps)}</For>
</Show>
Expand Down
41 changes: 19 additions & 22 deletions src/renderer/src/components/button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
import { cva, type VariantProps } from "class-variance-authority";
import { Component, JSX, splitProps } from "solid-js";
import { twMerge } from "tailwind-merge";

const buttonStyles = cva(
["rounded-lg", "transition-colors", "duration-200", "ease-in-out", "font-medium"],
{
variants: {
variant: {
primary: "bg-text text-thick-material hover:bg-text/80",
secondary: "bg-surface text-text ring-inset ring-1 ring-stroke hover:bg-surface/40",
outlined: "bg-transparent border-stroke border-solid text-text hover:bg-surface",
ghost: "rounded-full border-none text-xl hover:bg-surface",
link: "bg-transparent text-text hover:underline text-decoration-2 underline-offset-2",
},
size: {
medium: "px-4 py-2",
large: "px-7 py-2.5",
icon: "grid place-items-center aspect-square size-9 p-1 -m-2",
},
const buttonStyles = cva(["rounded-lg transition-colors duration-200 ease font-medium"], {
variants: {
variant: {
primary: "bg-text text-thick-material hover:bg-text/80",
secondary: "bg-surface text-text hover:bg-surface/40 border-stroke border border-solid",
outlined: "bg-transparent border-stroke text-text hover:bg-surface border border-solid",
ghost: "border-transparent hover:bg-surface",
link: "bg-transparent text-text hover:underline text-decoration-2 underline-offset-2",
},
defaultVariants: {
variant: "primary",
size: "medium",
size: {
medium: "px-4 py-2",
large: "px-7 py-2.5",
icon: "grid place-items-center aspect-square size-9 p-1 -m-2",
square: "grid place-items-center aspect-square h-10",
},
},
);
defaultVariants: {
variant: "primary",
size: "medium",
},
});

type ButtonProps = JSX.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof buttonStyles>;

Expand All @@ -33,7 +30,7 @@ const Button: Component<ButtonProps> = (props) => {

return (
<button
class={twMerge(buttonStyles({ variant: local.variant, size: local.size }), local.class)}
class={buttonStyles({ variant: local.variant, size: local.size, class: local.class })}
{...others}
>
{local.children}
Expand Down
65 changes: 65 additions & 0 deletions src/renderer/src/components/dropdown-list/DropdownList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import DropdownListItem from "./DropdownListItem";
import { useRovingFocusGroup } from "@renderer/lib/roving-focus-group/rovingFocusGroup";
import { createContext, createSignal, JSX, ParentComponent, useContext } from "solid-js";
import { RawList } from "../raw-list/RawList";
import { TokenNamespace } from "@renderer/lib/tungsten/token";

export type Props = JSX.IntrinsicElements["div"];

export type Context = ReturnType<typeof useProviderValue>;
function useProviderValue() {
const namespace = new TokenNamespace();
let pointerLeaveTimeout: NodeJS.Timeout | undefined;

const [isHighlighted, setIsHighlighted] = createSignal(false);

const rovingFocusGroup = useRovingFocusGroup({
updateFocusOnHover: true,
onKeyUp: () => {
setIsHighlighted(true);
},
});

const handleItemPointerLeave = () => {
clearTimeout(pointerLeaveTimeout);
pointerLeaveTimeout = setTimeout(() => {
setIsHighlighted(false);
}, 60);
};

const handleItemPointerMove = () => {
setIsHighlighted(true);
};

return {
...rovingFocusGroup,
handleItemPointerMove,
isHighlighted,
handleItemPointerLeave,
namespace,
};
}

export const DropdownListContext = createContext<Context>();
const DropdownListRoot: ParentComponent<Props> = (props) => {
const value = useProviderValue();
return (
<DropdownListContext.Provider value={value}>
<RawList {...props} {...value.attrs} />
</DropdownListContext.Provider>
);
};

export function useDropdownList(): Context {
const state = useContext(DropdownListContext);
if (!state) {
throw new Error("useDropdownList needs to be used inisde of the `ListContext` component.");
}
return state;
}

const DropdownList = Object.assign(DropdownListRoot, {
Item: DropdownListItem,
});

export default DropdownList;
31 changes: 31 additions & 0 deletions src/renderer/src/components/dropdown-list/DropdownListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useDropdownList } from "./DropdownList";
import { Component, onCleanup } from "solid-js";
import { JSX } from "solid-js/jsx-runtime";
import { RawList } from "../raw-list/RawList";

export type Props = JSX.IntrinsicElements["button"];
const DropdownListItem: Component<Props> = (props) => {
const state = useDropdownList();
const value = state.namespace.create();
const { attrs, tabIndex, isSelected } = state.item(value, {
onPointerMove: state.handleItemPointerMove,
});

onCleanup(() => {
state.namespace.destroy(value);
});

return (
<RawList.Item
onPointerLeave={state.handleItemPointerLeave}
tabIndex={tabIndex()}
classList={{
"bg-overlay/30": state.isHighlighted() && isSelected(),
}}
{...attrs}
{...props}
/>
);
};

export default DropdownListItem;
19 changes: 0 additions & 19 deletions src/renderer/src/components/dropdown/Dropdown.tsx

This file was deleted.

18 changes: 0 additions & 18 deletions src/renderer/src/components/dropdown/DropdownList.tsx

This file was deleted.

16 changes: 0 additions & 16 deletions src/renderer/src/components/dropdown/DropdownListItem.tsx

This file was deleted.

15 changes: 0 additions & 15 deletions src/renderer/src/components/dropdown/DropdownSelectTrigger.tsx

This file was deleted.

15 changes: 0 additions & 15 deletions src/renderer/src/components/dropdown/DropdownTrigger.tsx

This file was deleted.

34 changes: 34 additions & 0 deletions src/renderer/src/components/input/Input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { cva, VariantProps } from "class-variance-authority";
import { Component, JSX, splitProps } from "solid-js";

export const inputStyles = cva(
[
"ring-offset-background placeholder:text-subtext flex h-[42px] w-full rounded-lg px-3.5 py-2 disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:bg-surface",
],
{
variants: {
variant: {
primary: "",
outlined:
"border border-stroke bg-transparent border-solid block focus-visible:border-grey-400",
},
},
defaultVariants: {
variant: "outlined",
},
},
);

type Props = JSX.IntrinsicElements["input"] & VariantProps<typeof inputStyles>;
export const Input: Component<Props> = (_props) => {
const [props, rest] = splitProps(_props, ["class", "variant"]);
return (
<input
{...rest}
class={inputStyles({
variant: props.variant,
class: props.class,
})}
/>
);
};
Loading

0 comments on commit 338033e

Please sign in to comment.