feat: Instances

This commit is contained in:
LynithDev 2024-03-16 22:10:11 +01:00
parent af3bc0f1ee
commit 8bb0be03fd
12 changed files with 164 additions and 30 deletions

View file

@ -17,12 +17,14 @@
"@tauri-apps/plugin-shell": "2.0.0-beta.2",
"@untitled-theme/icons-solid": "^0.6.0",
"solid-js": "^1.7.8",
"solid-transition-group": "^0.2.3"
"solid-transition-group": "^0.2.3",
"uuid": "^9.0.1"
},
"devDependencies": {
"@solid/eslint-config-base": "^0.6.0",
"@stylistic/eslint-plugin-ts": "^1.7.0",
"@tauri-apps/cli": "2.0.0-beta.9",
"@types/uuid": "^9.0.8",
"@typescript-eslint/parser": "^7.2.0",
"autoprefixer": "^10.4.18",
"eslint": "^8.57.0",

15
pnpm-lock.yaml generated
View file

@ -23,6 +23,9 @@ dependencies:
solid-transition-group:
specifier: ^0.2.3
version: 0.2.3(solid-js@1.8.15)
uuid:
specifier: ^9.0.1
version: 9.0.1
devDependencies:
'@solid/eslint-config-base':
@ -34,6 +37,9 @@ devDependencies:
'@tauri-apps/cli':
specifier: 2.0.0-beta.9
version: 2.0.0-beta.9
'@types/uuid':
specifier: ^9.0.8
version: 9.0.8
'@typescript-eslint/parser':
specifier: ^7.2.0
version: 7.2.0(eslint@8.57.0)(typescript@5.4.2)
@ -1009,6 +1015,10 @@ packages:
resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
dev: true
/@types/uuid@9.0.8:
resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
dev: true
/@typescript-eslint/eslint-plugin@7.2.0(@typescript-eslint/parser@7.2.0)(eslint@8.57.0)(typescript@5.4.2):
resolution: {integrity: sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==}
engines: {node: ^16.0.0 || >=18.0.0}
@ -3591,6 +3601,11 @@ packages:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: true
/uuid@9.0.1:
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
hasBin: true
dev: false
/validate-html-nesting@1.2.2:
resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==}
dev: true

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

View file

@ -15,16 +15,4 @@ img { -webkit-user-drag: none; }
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);
}
h4 { @apply text-lg font-medium; }

3
src/types/game.d.ts vendored Normal file
View file

@ -0,0 +1,3 @@
declare namespace game {
export type Client = 'fabric' | 'forge' | 'quilt' | 'vanilla' | 'other';
}

View file

@ -12,14 +12,18 @@ function App(props: ParentProps) {
}
return (
<main class='flex flex-col bg-primary min-h-screen text-white'>
<main class='flex flex-col bg-primary min-h-screen text-white overflow-hidden'>
<WindowFrame />
<div class='flex flex-col flex-1 overflow-x-hidden px-8'>
<div class='flex flex-col flex-1 overflow-hidden px-8'>
<Navbar />
{ /* eslint-disable-next-line @typescript-eslint/no-use-before-define */ }
<AnimatedRoutes>
{props.children}
</AnimatedRoutes>
{/* // TODO fix overflow */}
<div class=''>
{ /* eslint-disable-next-line @typescript-eslint/no-use-before-define */ }
<AnimatedRoutes>
{props.children}
</AnimatedRoutes>
</div>
</div>
</main>
);

View file

@ -1,5 +1,5 @@
import { A } from '@solidjs/router';
import { ParentProps, createSignal } from 'solid-js';
import { createSignal } from 'solid-js';
import PolyfrostFull from './logos/PolyfrostFull';
import AccountPopup from './overlay/AccountPopup';

View file

@ -1,7 +1,7 @@
.textfield {
@apply bg-component-bg [&:not(:focus-within)]:hover:bg-component-bg-hover focus-within:bg-component-bg-pressed disabled:bg-component-bg-disabled;
@apply border border-gray-.5 text-fg-primary fill-fg-primary;
@apply rounded-lg px-2.5 py-1;
@apply rounded-lg px-2.5 py-1.5;
@apply flex flex-row gap-x-1.5;

View file

@ -1,4 +1,4 @@
import { JSX, splitProps } from 'solid-js';
import { JSX, createUniqueId, splitProps } from 'solid-js';
import styles from './TextField.module.scss';
type TextFieldProps = {
@ -8,13 +8,14 @@ type TextFieldProps = {
function TextField(props: TextFieldProps) {
const [fieldProps, rest] = splitProps(props, ['iconLeft', 'iconRight']);
const id = createUniqueId();
return (
<div class={styles.textfield}>
<label for={id} class={styles.textfield}>
{fieldProps.iconLeft && <span class={styles.icon}>{fieldProps.iconLeft}</span>}
<input type="text" {...rest} />
<input id={id} type="text" {...rest} />
{fieldProps.iconRight && <span class={styles.icon}>{fieldProps.iconRight}</span>}
</div>
</label>
);
}

View file

@ -1,10 +1,13 @@
import {
CheckIcon, DotsVerticalIcon, Download01Icon, PlayIcon, PlusIcon, SearchMdIcon,
CheckIcon, DotsVerticalIcon, Download01Icon, HeartRoundedIcon, PlayIcon, PlusIcon, SearchMdIcon,
} from '@untitled-theme/icons-solid';
import { createEffect, createSignal, For } from 'solid-js';
import image from '../../assets/images/header.png';
import Button from '../components/base/Button';
import Tag from '../components/base/Tag';
import TextField from '../components/base/TextField';
import defaultCover from '../../assets/images/default_instance_cover.jpg';
import { upperFirst } from '../../utils/string';
// TODO: Replace this into it's own component
function OneConfigLogo() {
@ -49,10 +52,118 @@ function Banner() {
);
}
function HomePage() {
type InstanceCardProps = {
name: string,
version: string,
client: game.Client,
mods?: number,
cover?: string,
lastPlayed?: number,
};
function InstanceCard(props: InstanceCardProps) {
return (
<div class='flex flex-col gap-y-6'>
<div class='h-[152px] group flex flex-col rounded-xl bg-component-bg hover:bg-component-bg-hover active:bg-component-bg-pressed border border-gray-.5 overflow-hidden'>
<div class='flex-1 relative overflow-hidden'>
<div class='absolute h-full w-full group-hover:scale-110 transition-transform'>
<img
class={`object-cover h-full w-full ${props.cover ? '' : ' filter grayscale'}`}
src={props.cover || defaultCover}
/>
</div>
</div>
<div class='z-10 p-3 flex flex-row items-center justify-between'>
<div class='flex flex-col gap-1.5'>
<p class='h-4 font-semibold'>{props.name}</p>
<p class='h-4 text-xs'>
{upperFirst(props.client)} {props.version} {props.mods && `• ${props.mods} mods`}
</p>
</div>
<Button styleType='icon' class='w-8 h-8'>
<DotsVerticalIcon />
</Button>
</div>
</div>
);
}
type InstanceGroupProps = {
title: string,
instances: InstanceCardProps[],
};
function InstanceGroup(props: InstanceGroupProps) {
const [sorted, setSorted] = createSignal<InstanceCardProps[]>([]);
createEffect(() => {
setSorted(props.instances.sort((a, b) => {
if (a.lastPlayed && b.lastPlayed) {
return b.lastPlayed - a.lastPlayed;
}
return 0;
}));
});
return (
<div class='flex flex-col gap-y-4'>
<h4>{props.title}</h4>
<div class='grid grid-cols-4 gap-4'>
<For each={sorted()}>{(instance) => (
<InstanceCard {...instance} />
)}</For>
</div>
</div>
);
}
function HomePage() {
const myInstances: InstanceCardProps[] = [
{
name: 'Hypixel',
client: 'vanilla',
version: '1.8.9',
},
{
name: 'OneConfig ??',
client: 'forge',
version: '1.8.9',
mods: 12,
},
{
name: 'Fabulously Optimised',
client: 'fabric',
version: '1.20.4',
mods: 48,
},
{
name: 'sus client',
client: 'other',
version: '1.8.9',
},
{
name: 'OneConfig ??',
client: 'forge',
version: '1.8.9',
mods: 12,
},
{
name: 'Fabulously Optimised',
client: 'fabric',
version: '1.20.4',
mods: 48,
},
{
name: 'sus client',
client: 'other',
version: '1.8.9',
},
];
return (
<div class='flex flex-col gap-y-4 text-fg-primary'>
<Banner />
<div class='flex flex-row justify-between items-center'>
<div>
<TextField iconLeft={<SearchMdIcon />} placeholder="Search for something..." />
@ -62,6 +173,9 @@ function HomePage() {
<Button styleType='secondary' iconLeft={<Download01Icon />}>From URL</Button>
</div>
</div>
<InstanceGroup title='Hypixel' instances={myInstances} />
<InstanceGroup title='Hypixel' instances={myInstances} />
</div>
);
}

View file

@ -1,4 +1,4 @@
function isDev() {
export function isDev() {
return window.location.host.startsWith('localhost:');
}

7
src/utils/string.ts Normal file
View file

@ -0,0 +1,7 @@
export function upperFirst(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
export default {
upperFirst,
};