feat: Instances
This commit is contained in:
parent
af3bc0f1ee
commit
8bb0be03fd
12 changed files with 164 additions and 30 deletions
|
|
@ -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
15
pnpm-lock.yaml
generated
|
|
@ -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
|
||||
|
|
|
|||
BIN
src/assets/images/default_instance_cover.jpg
Normal file
BIN
src/assets/images/default_instance_cover.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 321 KiB |
|
|
@ -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
3
src/types/game.d.ts
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
declare namespace game {
|
||||
export type Client = 'fabric' | 'forge' | 'quilt' | 'vanilla' | 'other';
|
||||
}
|
||||
|
|
@ -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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
function isDev() {
|
||||
export function isDev() {
|
||||
return window.location.host.startsWith('localhost:');
|
||||
}
|
||||
|
||||
|
|
|
|||
7
src/utils/string.ts
Normal file
7
src/utils/string.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export function upperFirst(str: string): string {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
export default {
|
||||
upperFirst,
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue