feat: Added mod cards component
This commit is contained in:
parent
4754374476
commit
09b73dc55e
6 changed files with 135 additions and 76 deletions
|
|
@ -42,12 +42,12 @@ h4 { @apply text-lg font-medium; }
|
|||
}
|
||||
|
||||
.page-animation-enter-active, .page-animation-leave-active {
|
||||
transition: opacity 160ms, transform 175ms;
|
||||
transition: opacity 130ms, transform 155ms;
|
||||
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
.page-animation-enter, .page-animation-leave-to {
|
||||
opacity: 0;
|
||||
.page-animation-enter {
|
||||
opacity: 0.1;
|
||||
transform: translateX(-75px);
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +56,11 @@ h4 { @apply text-lg font-medium; }
|
|||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.page-animation-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(75px);
|
||||
}
|
||||
|
||||
.noti-animation-enter-active, .noti-animation-leave-active {
|
||||
transition: opacity 160ms, transform 175ms;
|
||||
transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
|
|
|
|||
13
desktop/src/types/global.d.ts
vendored
13
desktop/src/types/global.d.ts
vendored
|
|
@ -1,4 +1,17 @@
|
|||
declare namespace globalThis {
|
||||
export type WithIndex<T> = T & { index: number }
|
||||
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
|
||||
}
|
||||
|
||||
// TODO remove in place for specta-generated types
|
||||
interface Mod {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
author: string;
|
||||
icon_url: string;
|
||||
provider: Provider;
|
||||
page_url: string;
|
||||
downloads: number;
|
||||
ratings: number;
|
||||
}
|
||||
62
desktop/src/ui/components/content/ModCard.tsx
Normal file
62
desktop/src/ui/components/content/ModCard.tsx
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import { Download01Icon, HeartIcon } from '@untitled-theme/icons-solid';
|
||||
import { useNavigate } from '@solidjs/router';
|
||||
import { abbreviateNumber } from '../../../utils/primitives';
|
||||
import BrowserMod from '~ui/pages/browser/BrowserMod';
|
||||
|
||||
// TODO: Remove in place for specta generated types
|
||||
export enum Provider {
|
||||
Curseforge,
|
||||
Modrinth,
|
||||
Polyfrost,
|
||||
Skyclient,
|
||||
}
|
||||
|
||||
function ModCard(props: Mod) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
function redirect() {
|
||||
navigate(BrowserMod.getUrl({
|
||||
id: props.id,
|
||||
provider: Provider[props.provider] || 'unknown',
|
||||
}));
|
||||
}
|
||||
|
||||
return (
|
||||
<div onClick={redirect} class="flex flex-col overflow-hidden rounded-lg bg-component-bg max-w-53 min-w-53 w-full max-h-68 min-h-68 h-full">
|
||||
<div class="relative h-28 overflow-hidden flex justify-center items-center">
|
||||
<img class="absolute filter-blur-xl z-0 max-w-none w-7/6" src={props.icon_url} alt={`Icon for ${props.name}`} />
|
||||
<img class="relative w-2/5 aspect-ratio-square z-1 rounded-2xl" src={props.icon_url} alt={`Icon for ${props.name}`} />
|
||||
</div>
|
||||
<div class="flex flex-col flex-1 p-3 gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<h5 class="font-medium text-fg-primary">{props.name}</h5>
|
||||
<p class="text-fg-secondary text-xs">
|
||||
By
|
||||
{' '}
|
||||
<span class="text-fg-primary">{props.author}</span>
|
||||
{' '}
|
||||
on
|
||||
{' '}
|
||||
{Provider[props.provider]}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="text-fg-secondary text-sm flex-1">{props.description}</p>
|
||||
|
||||
<div class="flex flex-row gap-4 text-xs">
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<Download01Icon class="w-4 h-4" />
|
||||
{abbreviateNumber(props.downloads)}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<HeartIcon class="w-4 h-4" />
|
||||
{abbreviateNumber(props.ratings)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ModCard;
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
import { Download01Icon, FileCode01Icon, FilterLinesIcon, HeartIcon, SearchMdIcon } from '@untitled-theme/icons-solid';
|
||||
import { type Accessor, For, type Setter, createEffect, createSignal } from 'solid-js';
|
||||
import { Download01Icon, FileCode01Icon, FilterLinesIcon, SearchMdIcon } from '@untitled-theme/icons-solid';
|
||||
import { For, createSignal } from 'solid-js';
|
||||
import Button from '~ui/components/base/Button';
|
||||
import Dropdown from '~ui/components/base/Dropdown';
|
||||
import TextField from '~ui/components/base/TextField';
|
||||
import ScrollableContainer from '~ui/components/ScrollableContainer';
|
||||
import { abbreviateNumber } from '~utils/primitives';
|
||||
import ModCard, { Provider } from '~ui/components/content/ModCard';
|
||||
import createSortable from '~utils/sorting';
|
||||
|
||||
interface CardProps {
|
||||
|
|
@ -15,13 +14,6 @@ interface CardProps {
|
|||
provider: Provider;
|
||||
};
|
||||
|
||||
enum Provider {
|
||||
Curseforge,
|
||||
Modrinth,
|
||||
Polyfrost,
|
||||
Skyclient,
|
||||
}
|
||||
|
||||
interface BrowserFilters {
|
||||
provider: Provider[]; // TODO: Change with Provider types from Rust
|
||||
}
|
||||
|
|
@ -90,22 +82,25 @@ function BrowserMain() {
|
|||
);
|
||||
}
|
||||
|
||||
export const modStore: Mod[] = [
|
||||
{
|
||||
id: '1yIQcc2b',
|
||||
name: 'EvergreenHUD',
|
||||
description: 'Improves your heads up display.',
|
||||
author: 'Polyfrost',
|
||||
icon_url: 'https://cdn.modrinth.com/data/1yIQcc2b/icon.png',
|
||||
page_url: 'https://modrinth.com/mod/evergreenhud',
|
||||
provider: Provider.Modrinth,
|
||||
downloads: 281700,
|
||||
ratings: 220,
|
||||
},
|
||||
];
|
||||
|
||||
const _modRowData: ModsRowProps[] = [
|
||||
{
|
||||
header: 'Highly Endorsed',
|
||||
category: 'endorsed',
|
||||
mods: [
|
||||
{
|
||||
name: 'EvergreenHUD',
|
||||
description: 'Improves your heads up display.',
|
||||
author: 'Polyfrost',
|
||||
icon_url: 'https://cdn.modrinth.com/data/1yIQcc2b/icon.png',
|
||||
page_url: 'https://modrinth.com/mod/evergreenhud',
|
||||
provider: Provider.Modrinth,
|
||||
downloads: 281700,
|
||||
ratings: 220,
|
||||
},
|
||||
],
|
||||
mods: modStore,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -115,17 +110,6 @@ interface ModsRowProps {
|
|||
mods: Mod[];
|
||||
};
|
||||
|
||||
interface Mod {
|
||||
name: string;
|
||||
description: string;
|
||||
author: string;
|
||||
icon_url: string;
|
||||
provider: Provider;
|
||||
page_url: string;
|
||||
downloads: number;
|
||||
ratings: number;
|
||||
}
|
||||
|
||||
function ModsRow(props: ModsRowProps) {
|
||||
return (
|
||||
<div class="flex flex-col flex-1 gap-3">
|
||||
|
|
@ -144,43 +128,4 @@ function ModsRow(props: ModsRowProps) {
|
|||
);
|
||||
}
|
||||
|
||||
function ModCard(props: Mod) {
|
||||
return (
|
||||
<div class="flex flex-col overflow-hidden rounded-lg bg-component-bg max-w-53 min-w-53 w-full max-h-68 min-h-68 h-full">
|
||||
<div class="relative h-28 overflow-hidden flex justify-center items-center">
|
||||
<img class="absolute filter-blur-xl z-0 max-w-none w-7/6" src={props.icon_url} alt={`Icon for ${props.name}`} />
|
||||
<img class="relative w-2/5 aspect-ratio-square z-1 rounded-2xl" src={props.icon_url} alt={`Icon for ${props.name}`} />
|
||||
</div>
|
||||
<div class="flex flex-col flex-1 p-3 gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<h5 class="font-medium text-fg-primary">{props.name}</h5>
|
||||
<p class="text-fg-secondary text-xs">
|
||||
By
|
||||
{' '}
|
||||
<span class="text-fg-primary">{props.author}</span>
|
||||
{' '}
|
||||
on
|
||||
{' '}
|
||||
{Provider[props.provider]}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="text-fg-secondary text-sm flex-1">{props.description}</p>
|
||||
|
||||
<div class="flex flex-row gap-4 text-xs">
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<Download01Icon class="w-4 h-4" />
|
||||
{abbreviateNumber(props.downloads)}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<HeartIcon class="w-4 h-4" />
|
||||
{abbreviateNumber(props.ratings)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BrowserMain;
|
||||
|
|
|
|||
32
desktop/src/ui/pages/browser/BrowserMod.tsx
Normal file
32
desktop/src/ui/pages/browser/BrowserMod.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { type Params, useSearchParams } from '@solidjs/router';
|
||||
import { Match, Switch } from 'solid-js';
|
||||
|
||||
interface BrowserModParams extends Params {
|
||||
id: string;
|
||||
provider: string;
|
||||
}
|
||||
|
||||
function BrowserMod() {
|
||||
const [params] = useSearchParams<BrowserModParams>();
|
||||
const isInvalid = !params.id || !params.provider;
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Match when={isInvalid === true}>
|
||||
{/* TODO */}
|
||||
<div>uh oh this doesnt exist</div>
|
||||
</Match>
|
||||
<Match when={isInvalid === false}>
|
||||
<div>
|
||||
{JSON.stringify(params)}
|
||||
</div>
|
||||
</Match>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
|
||||
BrowserMod.getUrl = function (params: BrowserModParams): string {
|
||||
return `/browser/mod?id=${params.id}&fprovider=${params.provider}`;
|
||||
};
|
||||
|
||||
export default BrowserMod;
|
||||
|
|
@ -2,12 +2,14 @@ import { Route } from '@solidjs/router';
|
|||
import type { ParentProps } from 'solid-js';
|
||||
import BrowserMain from './BrowserMain';
|
||||
import BrowserCategory from './BrowserCategory';
|
||||
import BrowserMod from './BrowserMod';
|
||||
|
||||
function BrowserRoutes() {
|
||||
return (
|
||||
<>
|
||||
<Route path="/" component={BrowserMain} />
|
||||
<Route path="/category" component={BrowserCategory} />
|
||||
<Route path="/mod" component={BrowserMod} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue