feat: Start work on Onboarding experience
This commit is contained in:
parent
bfaa6ceb3a
commit
7ef4c4bbb6
14 changed files with 310 additions and 97 deletions
46
apps/frontend/src/RootLayout.tsx
Normal file
46
apps/frontend/src/RootLayout.tsx
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { PROGRAM_INFO } from '@onelauncher/client/bindings';
|
||||||
|
import type { ParentProps } from 'solid-js';
|
||||||
|
import { MultiProvider } from './ui/components/MultiProvider';
|
||||||
|
import { AccountControllerProvider } from './ui/components/overlay/account/AddAccountModal';
|
||||||
|
import { ClusterModalControllerProvider } from './ui/components/overlay/cluster/ClusterCreationModal';
|
||||||
|
import { ModalProvider, ModalRenderer } from './ui/components/overlay/Modal';
|
||||||
|
import NotificationOverlay from './ui/components/overlay/notifications/NotificationOverlay';
|
||||||
|
import WindowFrame from './ui/components/WindowFrame';
|
||||||
|
import { BrowserProvider } from './ui/hooks/useBrowser';
|
||||||
|
import { SettingsProvider } from './ui/hooks/useSettings';
|
||||||
|
|
||||||
|
function RootLayout(props: ParentProps) {
|
||||||
|
if (PROGRAM_INFO.dev_build !== true)
|
||||||
|
document.addEventListener('contextmenu', e => e.preventDefault());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GlobalContexts>
|
||||||
|
<main class="h-screen max-h-screen min-h-screen w-full flex flex-col overflow-hidden bg-page text-fg-primary">
|
||||||
|
<WindowFrame />
|
||||||
|
|
||||||
|
{props.children}
|
||||||
|
|
||||||
|
<NotificationOverlay />
|
||||||
|
<ModalRenderer />
|
||||||
|
</main>
|
||||||
|
</GlobalContexts>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RootLayout;
|
||||||
|
|
||||||
|
function GlobalContexts(props: ParentProps) {
|
||||||
|
return (
|
||||||
|
<MultiProvider
|
||||||
|
values={[
|
||||||
|
ModalProvider,
|
||||||
|
SettingsProvider,
|
||||||
|
AccountControllerProvider,
|
||||||
|
ClusterModalControllerProvider,
|
||||||
|
BrowserProvider,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</MultiProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<svg width="319" height="277" viewBox="0 0 319 277" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M123.043 246.222C190.998 246.222 246.086 191.104 246.086 123.111C246.086 55.1187 190.998 0 123.043 0C55.0882 0 0 55.1187 0 123.111C0 191.104 55.0882 246.222 123.043 246.222Z" fill="url(#paint0_linear_3343_6724)"/>
|
||||||
|
<mask id="mask0_3343_6724" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="247" height="247">
|
||||||
|
<path d="M123.043 246.222C190.998 246.222 246.086 191.104 246.086 123.111C246.086 55.1187 190.998 0 123.043 0C55.0882 0 0 55.1187 0 123.111C0 191.104 55.0882 246.222 123.043 246.222Z" fill="white"/>
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_3343_6724)">
|
||||||
|
<path opacity="0.77" d="M206.791 198.326C203.4 187.661 211.376 176.767 203.959 159.122C196.542 141.478 190.524 145.731 184.325 134.945C178.126 124.159 185.887 120.568 179.165 115.976C175.679 113.595 172.615 115.463 169.434 117.33C166.478 119.064 163.422 120.799 159.83 119.132C152.369 115.668 153.317 106.251 147.467 100.365C141.616 94.4799 107.864 101.061 109.737 86.285C111.61 71.5094 161.369 52.1559 168.568 52.1604C175.768 52.165 179.291 64.7588 191.038 66.9406C196.782 68.0075 203.408 65.3447 209.862 62.6739C216.61 59.8868 223.172 57.1008 228.346 58.577C238.469 61.4656 318.417 137.044 318.417 137.044L233.795 216.383C217.533 201.777 210.185 208.99 206.791 198.326ZM89.7868 209.651C81.1954 208.398 67.3428 194.749 59.86 181.648C52.3772 168.547 64.3032 163.962 59.86 157.254C55.4168 150.546 41.7636 140.598 39.9088 136.735C38.0541 132.873 45.6577 126.269 39.9088 118.155C34.16 110.041 25.776 118.292 16.9089 104.291C8.04187 90.2907 4.43945 62.1518 4.43945 62.1518L67.6197 -12.4319L79.4945 6.62298L96.3616 18.6457C96.3616 18.6457 120.111 31.7969 119.16 40.8023C118.209 49.8076 94.4248 52.8979 92.5586 54.6637C90.6925 56.4294 92.9004 63.8138 84.2419 71.2996C75.5833 78.7855 65.0563 75.3201 57.9198 84.607C57.9198 84.607 56.8386 90.2679 56.2849 96.2342C55.7312 102.201 55.7073 108.452 55.7073 108.452C57.7979 111.522 60.5891 110.014 64.2223 108.504C67.8134 107.014 72.2247 105.522 77.5975 108.452C88.4037 114.344 98.9341 132.02 98.9341 132.02C98.9341 132.02 123.043 133.197 125.814 140.613C128.586 148.03 111.874 158.585 110.016 161.686C108.158 164.787 111.47 169.527 107.522 175.765C103.574 182.003 99.2782 177.835 94.222 186.639C89.3595 195.105 97.6911 209.721 90.6993 209.722C90.3938 209.721 90.0889 209.697 89.7868 209.651Z" fill="url(#paint1_linear_3343_6724)" fill-opacity="0.8"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter0_d_3343_6724)">
|
||||||
|
<path d="M284.821 104.872H173.171C158.7 104.872 146.968 116.611 146.968 131.09V242.802C146.968 257.282 158.7 269.02 173.171 269.02H284.821C299.293 269.02 311.025 257.282 311.025 242.802V131.09C311.025 116.611 299.293 104.872 284.821 104.872Z" fill="url(#paint2_linear_3343_6724)"/>
|
||||||
|
<path d="M284.821 105.442H173.171C159.014 105.442 147.537 116.925 147.537 131.091V242.802C147.537 256.968 159.014 268.451 173.171 268.451H284.821C298.978 268.451 310.455 256.968 310.455 242.802V131.091C310.455 116.925 298.978 105.442 284.821 105.442Z" stroke="white" stroke-opacity="0.5"/>
|
||||||
|
</g>
|
||||||
|
<path d="M266.21 220.077L240.946 150.478C239.852 147.628 238.43 146.867 235.258 146.867H222.79C219.618 146.867 218.196 147.524 217.103 150.697L191.947 220.077C190.853 223.032 191.514 224.564 194.9 224.564H206.384C211.853 224.564 213.275 223.36 214.368 219.968L216.884 212.088H240.503L243.019 219.968C243.899 223.36 245.539 224.564 251.226 224.564H263.039C266.32 224.564 267.304 223.032 266.21 220.077ZM231.54 182.104L235.586 194.908H221.915L225.962 181.995C227.325 177.039 228.024 171.924 228.04 166.784H229.133C229.356 171.965 230.163 177.104 231.54 182.104Z" fill="#2B4BFF" fill-opacity="0.76"/>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_3343_6724" x="138.968" y="96.8723" width="176.058" height="176.148" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dx="-2" dy="-2"/>
|
||||||
|
<feGaussianBlur stdDeviation="3"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.078 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3343_6724"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3343_6724" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
<linearGradient id="paint0_linear_3343_6724" x1="63.244" y1="2.78205e-06" x2="195.749" y2="233.109" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#7A64FF"/>
|
||||||
|
<stop offset="0.481" stop-color="#415EFF"/>
|
||||||
|
<stop offset="1" stop-color="#2B4BFF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_3343_6724" x1="102.401" y1="-12.4319" x2="134.26" y2="220.105" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EAF6FF"/>
|
||||||
|
<stop offset="1" stop-color="#C6E1F5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_3343_6724" x1="190.607" y1="102.082" x2="254.159" y2="268.997" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#C8D6F5"/>
|
||||||
|
<stop offset="1" stop-color="#B6CCFC"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5 KiB |
|
|
@ -1,24 +1,34 @@
|
||||||
/* @refresh reload */
|
/* @refresh reload */
|
||||||
import { Route, Router } from '@solidjs/router';
|
import { Route, Router } from '@solidjs/router';
|
||||||
|
|
||||||
|
import App from '~ui/pages/App';
|
||||||
import BrowserRoot from '~ui/pages/browser/BrowserRoot';
|
import BrowserRoot from '~ui/pages/browser/BrowserRoot';
|
||||||
import ClusterRoot from '~ui/pages/cluster/ClusterRoot';
|
|
||||||
|
|
||||||
|
import ClusterRoot from '~ui/pages/cluster/ClusterRoot';
|
||||||
|
import Onboarding from '~ui/pages/onboarding/Onboarding';
|
||||||
import SettingsRoot from '~ui/pages/settings/SettingsRoot';
|
import SettingsRoot from '~ui/pages/settings/SettingsRoot';
|
||||||
import { render } from 'solid-js/web';
|
import { render } from 'solid-js/web';
|
||||||
import { bridge } from './imports';
|
import { bridge } from './imports';
|
||||||
import App from './ui/App';
|
import RootLayout from './RootLayout';
|
||||||
import HomePage from './ui/pages/Home';
|
import HomePage from './ui/pages/Home';
|
||||||
import UpdatesPage from './ui/pages/Updates';
|
import UpdatesPage from './ui/pages/Updates';
|
||||||
|
|
||||||
document.body.setAttribute('data-platform', bridge.PROGRAM_INFO.platform);
|
document.body.setAttribute('data-platform', bridge.PROGRAM_INFO.platform);
|
||||||
|
|
||||||
render(() => (
|
render(() => (
|
||||||
<Router root={App}>
|
<Router root={RootLayout}>
|
||||||
<Route component={HomePage} path="/" />
|
<Route component={App}>
|
||||||
<Route component={UpdatesPage} path="/updates" />
|
<Route component={HomePage} path="/" />
|
||||||
<Route children={<ClusterRoot.Routes />} component={ClusterRoot} path="/clusters" />
|
<Route component={UpdatesPage} path="/updates" />
|
||||||
<Route children={<SettingsRoot.Routes />} component={SettingsRoot} path="/settings" />
|
<Route children={<ClusterRoot.Routes />} component={ClusterRoot} path="/clusters" />
|
||||||
<Route children={<BrowserRoot.Routes />} component={BrowserRoot} path="/browser" />
|
<Route children={<SettingsRoot.Routes />} component={SettingsRoot} path="/settings" />
|
||||||
|
<Route children={<BrowserRoot.Routes />} component={BrowserRoot} path="/browser" />
|
||||||
|
</Route>
|
||||||
|
|
||||||
|
<Route
|
||||||
|
children={Onboarding.Routes}
|
||||||
|
component={Onboarding}
|
||||||
|
path="/onboarding"
|
||||||
|
/>
|
||||||
</Router>
|
</Router>
|
||||||
), document.getElementById('root') as HTMLElement);
|
), document.getElementById('root') as HTMLElement);
|
||||||
|
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
import { PROGRAM_INFO } from '@onelauncher/client/bindings';
|
|
||||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-solid';
|
|
||||||
import type { ParentProps } from 'solid-js';
|
|
||||||
import AnimatedRoutes from './components/AnimatedRoutes';
|
|
||||||
import ErrorBoundary from './components/ErrorBoundary';
|
|
||||||
import { MultiProvider } from './components/MultiProvider';
|
|
||||||
import Navbar from './components/Navbar';
|
|
||||||
import { AccountControllerProvider } from './components/overlay/account/AddAccountModal';
|
|
||||||
import { ClusterModalControllerProvider } from './components/overlay/cluster/ClusterCreationModal';
|
|
||||||
import { ModalProvider, ModalRenderer } from './components/overlay/Modal';
|
|
||||||
import NotificationOverlay from './components/overlay/notifications/NotificationOverlay';
|
|
||||||
import WindowFrame from './components/WindowFrame';
|
|
||||||
import { BrowserProvider } from './hooks/useBrowser';
|
|
||||||
import { SettingsProvider } from './hooks/useSettings';
|
|
||||||
|
|
||||||
function App(props: ParentProps) {
|
|
||||||
if (PROGRAM_INFO.dev_build !== true)
|
|
||||||
document.addEventListener('contextmenu', e => e.preventDefault());
|
|
||||||
|
|
||||||
return (
|
|
||||||
<GlobalContexts>
|
|
||||||
<main class="h-screen max-h-screen min-h-screen w-full flex flex-col overflow-hidden bg-page text-fg-primary">
|
|
||||||
<WindowFrame />
|
|
||||||
<div class="flex flex-col px-8">
|
|
||||||
<Navbar />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="relative h-full w-full overflow-hidden">
|
|
||||||
<div class="absolute left-0 top-0 h-full w-full flex flex-col overflow-x-hidden">
|
|
||||||
<ErrorBoundary>
|
|
||||||
<OverlayScrollbarsComponent class="os-hide-horizontal-scrollbar absolute left-0 top-0 h-full w-full flex flex-col overflow-x-hidden overflow-y-auto px-8 pb-8">
|
|
||||||
<div class="h-full flex-1">
|
|
||||||
<AnimatedRoutes>
|
|
||||||
{props.children}
|
|
||||||
</AnimatedRoutes>
|
|
||||||
</div>
|
|
||||||
</OverlayScrollbarsComponent>
|
|
||||||
</ErrorBoundary>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<NotificationOverlay />
|
|
||||||
<ModalRenderer />
|
|
||||||
</main>
|
|
||||||
</GlobalContexts>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App;
|
|
||||||
|
|
||||||
function GlobalContexts(props: ParentProps) {
|
|
||||||
return (
|
|
||||||
<MultiProvider
|
|
||||||
values={[
|
|
||||||
ModalProvider,
|
|
||||||
SettingsProvider,
|
|
||||||
AccountControllerProvider,
|
|
||||||
ClusterModalControllerProvider,
|
|
||||||
BrowserProvider,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
</MultiProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
31
apps/frontend/src/ui/pages/App.tsx
Normal file
31
apps/frontend/src/ui/pages/App.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { OverlayScrollbarsComponent } from 'overlayscrollbars-solid';
|
||||||
|
import type { ParentProps } from 'solid-js';
|
||||||
|
import AnimatedRoutes from '../components/AnimatedRoutes';
|
||||||
|
import ErrorBoundary from '../components/ErrorBoundary';
|
||||||
|
import Navbar from '../components/Navbar';
|
||||||
|
|
||||||
|
function App(props: ParentProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class="flex flex-col px-8">
|
||||||
|
<Navbar />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="relative h-full w-full overflow-hidden">
|
||||||
|
<div class="absolute left-0 top-0 h-full w-full flex flex-col overflow-x-hidden">
|
||||||
|
<ErrorBoundary>
|
||||||
|
<OverlayScrollbarsComponent class="os-hide-horizontal-scrollbar absolute left-0 top-0 h-full w-full flex flex-col overflow-x-hidden overflow-y-auto px-8 pb-8">
|
||||||
|
<div class="h-full flex-1">
|
||||||
|
<AnimatedRoutes>
|
||||||
|
{props.children}
|
||||||
|
</AnimatedRoutes>
|
||||||
|
</div>
|
||||||
|
</OverlayScrollbarsComponent>
|
||||||
|
</ErrorBoundary>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
|
@ -6,19 +6,19 @@ import {
|
||||||
RefreshCw01Icon,
|
RefreshCw01Icon,
|
||||||
SearchMdIcon,
|
SearchMdIcon,
|
||||||
} from '@untitled-theme/icons-solid';
|
} from '@untitled-theme/icons-solid';
|
||||||
import { For, Show, onMount } from 'solid-js';
|
|
||||||
import type { Cluster } from '@onelauncher/client/bindings';
|
|
||||||
import BannerBackground from '../../assets/images/header.png';
|
|
||||||
import Button from '../components/base/Button';
|
|
||||||
import TextField from '../components/base/TextField';
|
|
||||||
import ClusterRoot from './cluster/ClusterRoot';
|
|
||||||
import { bridge } from '~imports';
|
import { bridge } from '~imports';
|
||||||
|
|
||||||
import ClusterCover from '~ui/components/game/ClusterCover';
|
import ClusterCover from '~ui/components/game/ClusterCover';
|
||||||
import { useClusterCreator } from '~ui/components/overlay/cluster/ClusterCreationModal';
|
import { useClusterCreator } from '~ui/components/overlay/cluster/ClusterCreationModal';
|
||||||
import { useLaunchCluster, useRecentCluster } from '~ui/hooks/useCluster';
|
import { useLaunchCluster, useRecentCluster } from '~ui/hooks/useCluster';
|
||||||
import useCommand from '~ui/hooks/useCommand';
|
import useCommand from '~ui/hooks/useCommand';
|
||||||
import { formatAsDuration, upperFirst } from '~utils';
|
import { formatAsDuration, upperFirst } from '~utils';
|
||||||
|
import { For, onMount, Show } from 'solid-js';
|
||||||
|
|
||||||
|
import type { Cluster } from '@onelauncher/client/bindings';
|
||||||
|
import BannerBackground from '../../assets/images/header.png';
|
||||||
|
import Button from '../components/base/Button';
|
||||||
|
import TextField from '../components/base/TextField';
|
||||||
|
import ClusterRoot from './cluster/ClusterRoot';
|
||||||
|
|
||||||
type GroupedClusters = Record<string, Cluster[]>;
|
type GroupedClusters = Record<string, Cluster[]>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,24 @@ function BrowserSidebar() {
|
||||||
</For>
|
</For>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
{/* <div class="flex flex-col gap-y-1">
|
||||||
|
<h6 class="my-1">Package Type</h6>
|
||||||
|
<Dropdown
|
||||||
|
onChange={index => controller.setSearchQuery(prev => ({
|
||||||
|
...prev,
|
||||||
|
package_types: [PACKAGE_TYPES[index] || 'mod'],
|
||||||
|
}))}
|
||||||
|
selected={() => PACKAGE_TYPES.indexOf(controller.searchQuery().package_types?.[0] || 'mod')}
|
||||||
|
>
|
||||||
|
<For each={PACKAGE_TYPES}>
|
||||||
|
{provider => (
|
||||||
|
<Dropdown.Row>
|
||||||
|
{provider}
|
||||||
|
</Dropdown.Row>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</Dropdown>
|
||||||
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
100
apps/frontend/src/ui/pages/onboarding/Onboarding.tsx
Normal file
100
apps/frontend/src/ui/pages/onboarding/Onboarding.tsx
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
import { Route, useLocation, useNavigate } from '@solidjs/router';
|
||||||
|
import { ChevronLeftIcon, ChevronRightIcon } from '@untitled-theme/icons-solid';
|
||||||
|
import AnimatedRoutes from '~ui/components/AnimatedRoutes';
|
||||||
|
import Button from '~ui/components/base/Button';
|
||||||
|
import PolyfrostFull from '~ui/components/logos/PolyfrostFull';
|
||||||
|
import { type JSX, type ParentProps } from 'solid-js';
|
||||||
|
import OnboardingLanguage from './OnboardingLanguage';
|
||||||
|
import OnboardingWelcome from './OnboardingWelcome';
|
||||||
|
|
||||||
|
const basePath = '/onboarding';
|
||||||
|
const OnboardingSteps = [
|
||||||
|
['/', OnboardingWelcome],
|
||||||
|
['/language', OnboardingLanguage],
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
function Onboarding(props: ParentProps) {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
const step = () => OnboardingSteps.findIndex(([path]) => location.pathname === basePath + path);
|
||||||
|
|
||||||
|
const canGoBack = () => step() > 0;
|
||||||
|
const canGoForward = () => step() < OnboardingSteps.length - 1;
|
||||||
|
|
||||||
|
const next = () => {
|
||||||
|
if (canGoForward())
|
||||||
|
navigate(basePath + OnboardingSteps[step() + 1]![0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const previous = () => {
|
||||||
|
if (canGoBack())
|
||||||
|
navigate(basePath + OnboardingSteps[step() - 1]![0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="h-full w-full flex flex-col p-8">
|
||||||
|
<div class="">
|
||||||
|
<PolyfrostFull />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 p-16">
|
||||||
|
<AnimatedRoutes>
|
||||||
|
{props.children}
|
||||||
|
</AnimatedRoutes>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full flex flex-row items-end justify-end">
|
||||||
|
<div class="w-1/3 flex flex-row items-stretch gap-x-8 [&>*]:w-full">
|
||||||
|
<Button
|
||||||
|
buttonStyle="secondary"
|
||||||
|
children="Previous"
|
||||||
|
disabled={!canGoBack()}
|
||||||
|
iconLeft={<ChevronLeftIcon />}
|
||||||
|
onClick={previous}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
children={canGoForward() ? 'Next' : 'Finish'}
|
||||||
|
iconRight={<ChevronRightIcon />}
|
||||||
|
onClick={next}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Onboarding.Steps = OnboardingSteps;
|
||||||
|
Onboarding.Routes = OnboardingSteps.map(([path, component]) => (
|
||||||
|
<Route component={component} path={path} />
|
||||||
|
));
|
||||||
|
|
||||||
|
export default Onboarding;
|
||||||
|
|
||||||
|
export interface OnboardingStepProps extends ParentProps {
|
||||||
|
title: string;
|
||||||
|
paragraph: string;
|
||||||
|
illustration: JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function OnboardingStep(props: OnboardingStepProps) {
|
||||||
|
return (
|
||||||
|
<div class="grid grid-cols-2 h-full w-full gap-x-16">
|
||||||
|
<div class="flex flex-col items-center justify-center">
|
||||||
|
{props.illustration}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-y-2">
|
||||||
|
<div class="flex flex-col gap-y-2">
|
||||||
|
<h1 class="text-2xl">{props.title}</h1>
|
||||||
|
<p class="text-lg text-fg-secondary line-height-normal">{props.paragraph}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-1 flex-col gap-y-2">
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
apps/frontend/src/ui/pages/onboarding/OnboardingLanguage.tsx
Normal file
16
apps/frontend/src/ui/pages/onboarding/OnboardingLanguage.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import Illustration from '~assets/illustrations/onboarding/language.svg?component-solid';
|
||||||
|
import { OnboardingStep } from './Onboarding';
|
||||||
|
|
||||||
|
function OnboardingLanguage() {
|
||||||
|
return (
|
||||||
|
<OnboardingStep
|
||||||
|
illustration={<Illustration />}
|
||||||
|
paragraph="Choose your preferred language."
|
||||||
|
title="Language"
|
||||||
|
>
|
||||||
|
<h1>lol</h1>
|
||||||
|
</OnboardingStep>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OnboardingLanguage;
|
||||||
13
apps/frontend/src/ui/pages/onboarding/OnboardingWelcome.tsx
Normal file
13
apps/frontend/src/ui/pages/onboarding/OnboardingWelcome.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { OnboardingStep } from './Onboarding';
|
||||||
|
|
||||||
|
function OnboardingWelcome() {
|
||||||
|
return (
|
||||||
|
<OnboardingStep
|
||||||
|
illustration={<span>todo :(</span>}
|
||||||
|
paragraph="OneLauncher is a powerful and easy-to-use launcher for your applications."
|
||||||
|
title="Welcome to OneLauncher!"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OnboardingWelcome;
|
||||||
|
|
@ -152,3 +152,4 @@ export function getPackageUrl(provider: Providers, id: string, package_type: Pac
|
||||||
|
|
||||||
export const LOADERS: Loader[] = ['vanilla', 'fabric', 'forge', 'neoforge', 'quilt'] as const;
|
export const LOADERS: Loader[] = ['vanilla', 'fabric', 'forge', 'neoforge', 'quilt'] as const;
|
||||||
export const PROVIDERS: Providers[] = ['Modrinth'] as const;
|
export const PROVIDERS: Providers[] = ['Modrinth'] as const;
|
||||||
|
export const PACKAGE_TYPES: PackageType[] = ['mod', 'resourcepack', 'datapack', 'shaderpack'] as const;
|
||||||
|
|
|
||||||
|
|
@ -57,12 +57,6 @@ impl Providers {
|
||||||
limit,
|
limit,
|
||||||
offset,
|
offset,
|
||||||
Some(|mut builder: FacetBuilder| {
|
Some(|mut builder: FacetBuilder| {
|
||||||
if let Some(game_versions) = game_versions {
|
|
||||||
for version in game_versions {
|
|
||||||
builder.and(Facet("versions".to_string(), FacetOperation::Eq, version));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(categories) = categories {
|
if let Some(categories) = categories {
|
||||||
for category in categories {
|
for category in categories {
|
||||||
builder.and(Facet(
|
builder.and(Facet(
|
||||||
|
|
@ -73,7 +67,25 @@ impl Providers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(game_versions) = game_versions {
|
||||||
|
for version in game_versions {
|
||||||
|
builder.and(Facet("versions".to_string(), FacetOperation::Eq, version));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(package_types) = package_types {
|
if let Some(package_types) = package_types {
|
||||||
|
if package_types.contains(&PackageType::Mod) || package_types.contains(&PackageType::ModPack) {
|
||||||
|
if let Some(loaders) = loaders {
|
||||||
|
for loader in loaders {
|
||||||
|
builder.and(Facet(
|
||||||
|
"categories".to_string(),
|
||||||
|
FacetOperation::Eq,
|
||||||
|
loader.to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for package_type in package_types {
|
for package_type in package_types {
|
||||||
builder.and(Facet(
|
builder.and(Facet(
|
||||||
"project_types".to_string(),
|
"project_types".to_string(),
|
||||||
|
|
@ -83,16 +95,6 @@ impl Providers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(loaders) = loaders {
|
|
||||||
for loader in loaders {
|
|
||||||
builder.or(Facet(
|
|
||||||
"categories".to_string(),
|
|
||||||
FacetOperation::Eq,
|
|
||||||
loader.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(open_source) = open_source {
|
if let Some(open_source) = open_source {
|
||||||
builder.and(Facet(
|
builder.and(Facet(
|
||||||
"open_source".to_string(),
|
"open_source".to_string(),
|
||||||
|
|
|
||||||
|
|
@ -236,6 +236,7 @@ impl FacetBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn or(&mut self, facet: Facet) -> &Self {
|
pub fn or(&mut self, facet: Facet) -> &Self {
|
||||||
let mut last_facet = self.facets.pop().unwrap_or_default();
|
let mut last_facet = self.facets.pop().unwrap_or_default();
|
||||||
last_facet.push(facet);
|
last_facet.push(facet);
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ pub enum PackageType {
|
||||||
/// Represents a resourcepack file
|
/// Represents a resourcepack file
|
||||||
ResourcePack,
|
ResourcePack,
|
||||||
/// Represents a shaderpack file
|
/// Represents a shaderpack file
|
||||||
|
#[serde(alias = "shader")]
|
||||||
ShaderPack,
|
ShaderPack,
|
||||||
/// Represents a modpack file
|
/// Represents a modpack file
|
||||||
ModPack,
|
ModPack,
|
||||||
|
|
@ -71,7 +72,7 @@ impl PackageType {
|
||||||
PackageType::Mod => "mod",
|
PackageType::Mod => "mod",
|
||||||
PackageType::DataPack => "datapack",
|
PackageType::DataPack => "datapack",
|
||||||
PackageType::ResourcePack => "resourcepack",
|
PackageType::ResourcePack => "resourcepack",
|
||||||
PackageType::ShaderPack => "shaderpack",
|
PackageType::ShaderPack => "shader",
|
||||||
PackageType::ModPack => "modpack",
|
PackageType::ModPack => "modpack",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -118,6 +119,7 @@ impl PackageType {
|
||||||
PackageType::DataPack,
|
PackageType::DataPack,
|
||||||
PackageType::ResourcePack,
|
PackageType::ResourcePack,
|
||||||
PackageType::ShaderPack,
|
PackageType::ShaderPack,
|
||||||
|
PackageType::ModPack,
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue