Add settings page & more
This commit is contained in:
16 files changed
+360
-40
No files matched your search
@@ -12,9 +12,12 @@
|
|||||||
"@fortawesome/react-fontawesome": "^3.3.0",
|
"@fortawesome/react-fontawesome": "^3.3.0",
|
||||||
"@tauri-apps/api": "2.10.1",
|
"@tauri-apps/api": "2.10.1",
|
||||||
"@tauri-apps/plugin-clipboard-manager": "~2",
|
"@tauri-apps/plugin-clipboard-manager": "~2",
|
||||||
|
"@tauri-apps/plugin-fs": "~2",
|
||||||
"@tauri-apps/plugin-http": "~2",
|
"@tauri-apps/plugin-http": "~2",
|
||||||
"@tauri-apps/plugin-notification": "~2",
|
"@tauri-apps/plugin-notification": "~2",
|
||||||
"@tauri-apps/plugin-opener": "~2",
|
"@tauri-apps/plugin-opener": "~2",
|
||||||
|
"@tauri-apps/plugin-os": "~2",
|
||||||
|
"@tauri-apps/plugin-store": "~2",
|
||||||
"next": "16.2.1",
|
"next": "16.2.1",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.4",
|
||||||
@@ -268,12 +271,18 @@
|
|||||||
|
|
||||||
"@tauri-apps/plugin-clipboard-manager": ["@tauri-apps/plugin-clipboard-manager@2.3.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-CUlb5Hqi2oZbcZf4VUyUH53XWPPdtpw43EUpCza5HWZJwxEoDowFzNUDt1tRUXA8Uq+XPn17Ysfptip33sG4eQ=="],
|
"@tauri-apps/plugin-clipboard-manager": ["@tauri-apps/plugin-clipboard-manager@2.3.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-CUlb5Hqi2oZbcZf4VUyUH53XWPPdtpw43EUpCza5HWZJwxEoDowFzNUDt1tRUXA8Uq+XPn17Ysfptip33sG4eQ=="],
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-fs": ["@tauri-apps/plugin-fs@2.4.5", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-dVxWWGE6VrOxC7/jlhyE+ON/Cc2REJlM35R3PJX3UvFw2XwYhLGQVAIyrehenDdKjotipjYEVc4YjOl3qq90fA=="],
|
||||||
|
|
||||||
"@tauri-apps/plugin-http": ["@tauri-apps/plugin-http@2.5.7", "", { "dependencies": { "@tauri-apps/api": "^2.10.1" } }, "sha512-+F2lEH/c9b0zSsOXKq+5hZNcd9F4IIKCK1T17RqMwpCmVnx2aoqY8yIBccCd25HTYUb3j6NPVbRax/m00hKG8A=="],
|
"@tauri-apps/plugin-http": ["@tauri-apps/plugin-http@2.5.7", "", { "dependencies": { "@tauri-apps/api": "^2.10.1" } }, "sha512-+F2lEH/c9b0zSsOXKq+5hZNcd9F4IIKCK1T17RqMwpCmVnx2aoqY8yIBccCd25HTYUb3j6NPVbRax/m00hKG8A=="],
|
||||||
|
|
||||||
"@tauri-apps/plugin-notification": ["@tauri-apps/plugin-notification@2.3.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg=="],
|
"@tauri-apps/plugin-notification": ["@tauri-apps/plugin-notification@2.3.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg=="],
|
||||||
|
|
||||||
"@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ=="],
|
"@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ=="],
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-os": ["@tauri-apps/plugin-os@2.3.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-n+nXWeuSeF9wcEsSPmRnBEGrRgOy6jjkSU+UVCOV8YUGKb2erhDOxis7IqRXiRVHhY8XMKks00BJ0OAdkpf6+A=="],
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-store": ["@tauri-apps/plugin-store@2.4.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-0ClHS50Oq9HEvLPhNzTNFxbWVOqoAp3dRvtewQBeqfIQ0z5m3JRnOISIn2ZVPCrQC0MyGyhTS9DWhHjpigQE7A=="],
|
||||||
|
|
||||||
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
||||||
|
|
||||||
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||||
|
|||||||
@@ -17,9 +17,12 @@
|
|||||||
"@fortawesome/react-fontawesome": "^3.3.0",
|
"@fortawesome/react-fontawesome": "^3.3.0",
|
||||||
"@tauri-apps/api": "2.10.1",
|
"@tauri-apps/api": "2.10.1",
|
||||||
"@tauri-apps/plugin-clipboard-manager": "~2",
|
"@tauri-apps/plugin-clipboard-manager": "~2",
|
||||||
|
"@tauri-apps/plugin-fs": "~2",
|
||||||
"@tauri-apps/plugin-http": "~2",
|
"@tauri-apps/plugin-http": "~2",
|
||||||
"@tauri-apps/plugin-notification": "~2",
|
"@tauri-apps/plugin-notification": "~2",
|
||||||
"@tauri-apps/plugin-opener": "~2",
|
"@tauri-apps/plugin-opener": "~2",
|
||||||
|
"@tauri-apps/plugin-os": "~2",
|
||||||
|
"@tauri-apps/plugin-store": "~2",
|
||||||
"next": "16.2.1",
|
"next": "16.2.1",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.4"
|
"react-dom": "19.2.4"
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ tauri-plugin-http = "2"
|
|||||||
tauri-plugin-opener = "2"
|
tauri-plugin-opener = "2"
|
||||||
tauri-plugin-notification = "2"
|
tauri-plugin-notification = "2"
|
||||||
tauri-plugin-clipboard-manager = "2"
|
tauri-plugin-clipboard-manager = "2"
|
||||||
|
tauri-plugin-store = "2"
|
||||||
|
tauri-plugin-fs = "2"
|
||||||
|
tauri-plugin-os = "2"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
"$schema": "../gen/schemas/desktop-schema.json",
|
"$schema": "../gen/schemas/desktop-schema.json",
|
||||||
"identifier": "default",
|
"identifier": "default",
|
||||||
"description": "Capability for the main window",
|
"description": "Capability for the main window",
|
||||||
"windows": ["main"],
|
"windows": [
|
||||||
|
"main"
|
||||||
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"core:default",
|
"core:default",
|
||||||
"opener:default",
|
"opener:default",
|
||||||
@@ -43,6 +45,9 @@
|
|||||||
"url": "https://games.lncvrt.xyz/api/berrydash/leaderboard/total"
|
"url": "https://games.lncvrt.xyz/api/berrydash/leaderboard/total"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"store:default",
|
||||||
|
"fs:default",
|
||||||
|
"os:default"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_os::init())
|
||||||
|
.plugin(tauri_plugin_fs::init())
|
||||||
|
.plugin(tauri_plugin_store::Builder::new().build())
|
||||||
.plugin(tauri_plugin_clipboard_manager::init())
|
.plugin(tauri_plugin_clipboard_manager::init())
|
||||||
.plugin(tauri_plugin_notification::init())
|
.plugin(tauri_plugin_notification::init())
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
|
|||||||
+36
-19
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import '@/styles/globals.css'
|
import '@/styles/globals.css'
|
||||||
import { Roboto } from 'next/font/google'
|
import { Roboto } from 'next/font/google'
|
||||||
import LauncherContext from '@/context/LauncherContext'
|
|
||||||
|
|
||||||
import Sidebar from '@/componets/Sidebar'
|
import Sidebar from '@/componets/Sidebar'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
@@ -13,12 +12,43 @@ import {
|
|||||||
isPermissionGranted,
|
isPermissionGranted,
|
||||||
requestPermission
|
requestPermission
|
||||||
} from '@tauri-apps/plugin-notification'
|
} from '@tauri-apps/plugin-notification'
|
||||||
|
import GlobalProvider from '@/providers/GlobalProvider'
|
||||||
|
import { SettingsProvider, useSettings } from '@/providers/SettingsProvider'
|
||||||
|
|
||||||
const roboto = Roboto({
|
const roboto = Roboto({
|
||||||
variable: '--font-roboto',
|
variable: '--font-roboto',
|
||||||
subsets: ['latin']
|
subsets: ['latin']
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function RootLayoutContent ({
|
||||||
|
children,
|
||||||
|
loading
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
loading: 0 | 1 | 2 | 3
|
||||||
|
}) {
|
||||||
|
const { theme } = useSettings()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<body className={theme + '-theme'}>
|
||||||
|
{loading == 3 ? (
|
||||||
|
<>
|
||||||
|
<Sidebar />
|
||||||
|
<main className='ml-60 relative'>{children}</main>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<p className='flex justify-center items-center h-screen w-screen text-6xl'>
|
||||||
|
{loading == 0
|
||||||
|
? 'Loading'
|
||||||
|
: loading == 1
|
||||||
|
? 'Failed to load launcher'
|
||||||
|
: 'Outdated launcher!'}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</body>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default function RootLayout ({
|
export default function RootLayout ({
|
||||||
children
|
children
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
@@ -67,24 +97,11 @@ export default function RootLayout ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang='en' className={roboto.className}>
|
<html lang='en' className={roboto.className}>
|
||||||
<body className='dark-theme'>
|
<GlobalProvider.Provider value={{ launcherManifest }}>
|
||||||
<LauncherContext.Provider value={{ launcherManifest }}>
|
<SettingsProvider>
|
||||||
{loading == 3 ? (
|
<RootLayoutContent loading={loading}>{children}</RootLayoutContent>
|
||||||
<>
|
</SettingsProvider>
|
||||||
<Sidebar />
|
</GlobalProvider.Provider>
|
||||||
<main className='ml-60 relative'>{children}</main>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<p className='flex justify-center items-center h-screen w-screen text-6xl'>
|
|
||||||
{loading == 0
|
|
||||||
? 'Loading'
|
|
||||||
: loading == 1
|
|
||||||
? 'Failed to load launcher'
|
|
||||||
: 'Outdated launcher!'}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</LauncherContext.Provider>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
export default function Home () {
|
export default function HomePage () {
|
||||||
return <div></div>
|
return <div></div>
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { Setting } from '@/componets/Setting'
|
||||||
|
import { copyToClipboard } from '@/lib/clipboard'
|
||||||
|
import { useSettings } from '@/providers/SettingsProvider'
|
||||||
|
import { app } from '@tauri-apps/api'
|
||||||
|
import { platform } from '@tauri-apps/plugin-os'
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
export default function SettingsPage () {
|
||||||
|
const {
|
||||||
|
notificationsAllowed,
|
||||||
|
sidebarAlwaysShowGames,
|
||||||
|
linuxUseWine,
|
||||||
|
linuxWineCommand,
|
||||||
|
theme,
|
||||||
|
settings
|
||||||
|
} = useSettings()
|
||||||
|
|
||||||
|
const [version, setVersion] = useState('')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
app.getVersion().then(setVersion)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p className='text-3xl ml-4 mt-4'>Settings</p>
|
||||||
|
<div className='ml-4 mt-4 bg-(--col1) border border-(--col3) rounded-lg p-4 w-fit h-fit'>
|
||||||
|
<Setting
|
||||||
|
label='Allow sending notifications'
|
||||||
|
value={notificationsAllowed}
|
||||||
|
onChange={async () => {
|
||||||
|
await settings?.set('notificationsAllowed', !notificationsAllowed)
|
||||||
|
}}
|
||||||
|
title='This setting does as you expect, allow the launcher to send notifications for when stuff like downloading is done.'
|
||||||
|
/>
|
||||||
|
<Setting
|
||||||
|
label='Always show games in sidebar'
|
||||||
|
value={sidebarAlwaysShowGames}
|
||||||
|
onChange={async () => {
|
||||||
|
await settings?.set(
|
||||||
|
'sidebarAlwaysShowGames',
|
||||||
|
!sidebarAlwaysShowGames
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
title="This setting will make it so when you are on a page like this, the games won't disappear."
|
||||||
|
/>
|
||||||
|
<Setting
|
||||||
|
label='Use wine if needed'
|
||||||
|
value={linuxUseWine}
|
||||||
|
onChange={async () => {
|
||||||
|
await settings?.set('linuxUseWine', !linuxUseWine)
|
||||||
|
}}
|
||||||
|
className={platform() == 'linux' ? '' : 'hidden'}
|
||||||
|
/>
|
||||||
|
<p hidden={!(platform() == 'linux' && linuxUseWine)}>Wine Command:</p>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
value={linuxWineCommand}
|
||||||
|
onChange={async e => {
|
||||||
|
await settings?.set('linuxWineCommand', e.target.value)
|
||||||
|
}}
|
||||||
|
className={`input-field my-1 ${
|
||||||
|
platform() == 'linux' && linuxWineCommand ? '' : 'hidden'
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
<div title='The theme you want the launcher to use.'>
|
||||||
|
<label className='text-lg'>Theme:</label>
|
||||||
|
<select
|
||||||
|
className='ml-2 bg-(--col2) border border-(--col4) rounded-md'
|
||||||
|
value={theme}
|
||||||
|
onChange={async e => {
|
||||||
|
await settings?.set('theme', e.target.value)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value={'dark'}>Dark (default)</option>
|
||||||
|
<option value={'red'}>Red</option>
|
||||||
|
<option value={'blue'}>Blue</option>
|
||||||
|
<option value={'purple'}>Purple</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
className='fixed bottom-1.5 right-1.5 rounded-md cursor-pointer px-1 border z-100 transition-colors btntheme1'
|
||||||
|
onClick={async () => {
|
||||||
|
await copyToClipboard('v' + version, true)
|
||||||
|
}}
|
||||||
|
title='The current launcher version.'
|
||||||
|
>
|
||||||
|
v{version}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import '@/styles/setting.css'
|
||||||
|
import { SettingProps } from '@/types/SettingProps'
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
|
import { faCheck } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
export function Setting ({
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
className,
|
||||||
|
title
|
||||||
|
}: SettingProps) {
|
||||||
|
return (
|
||||||
|
<div className={`flex items-center gap-2 mb-2 ${className}`} title={title}>
|
||||||
|
<label className='text-white text-lg'>{label}</label>
|
||||||
|
<div className='setting-checkbox-wrapper'>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
className='setting-checkbox'
|
||||||
|
checked={value}
|
||||||
|
onChange={() => onChange(!value)}
|
||||||
|
/>
|
||||||
|
{value && <FontAwesomeIcon icon={faCheck} className='fa-check-icon' />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
import '@/styles/sidebar.css'
|
import '@/styles/sidebar.css'
|
||||||
import { Lexend } from 'next/font/google'
|
import { Lexend } from 'next/font/google'
|
||||||
import Image from 'next/image'
|
|
||||||
|
|
||||||
import Icon from '@/assets/Icon.png'
|
import Icon from '@/assets/Icon.png'
|
||||||
|
|
||||||
|
import Image from 'next/image'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { usePathname } from 'next/navigation'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
|
import { faCog } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faDiscord } from '@fortawesome/free-brands-svg-icons'
|
import { faDiscord } from '@fortawesome/free-brands-svg-icons'
|
||||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||||
|
|
||||||
@@ -15,13 +18,22 @@ const lexend = Lexend({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export default function Sidebar () {
|
export default function Sidebar () {
|
||||||
|
const pathname = usePathname()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={'sidebar ' + lexend.className}>
|
<aside className='sidebar'>
|
||||||
<div className='logo'>
|
<div className='logo'>
|
||||||
<Image src={Icon} width={36} height={36} alt='' />
|
<Image src={Icon} width={36} height={36} alt='' />
|
||||||
<p>Lncvrt Games Launcher</p>
|
<p className={lexend.className}>Lncvrt Games Launcher</p>
|
||||||
</div>
|
</div>
|
||||||
<nav>
|
<nav>
|
||||||
|
<Link
|
||||||
|
draggable={false}
|
||||||
|
href='/settings'
|
||||||
|
className={`link ${pathname === '/settings' ? 'active' : ''}`}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faCog} className='mr-1' /> Settings
|
||||||
|
</Link>
|
||||||
<button
|
<button
|
||||||
onClick={() => openUrl('https://games.lncvrt.xyz/discord')}
|
onClick={() => openUrl('https://games.lncvrt.xyz/discord')}
|
||||||
className='link mr-auto'
|
className='link mr-auto'
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { createContext, useContext } from 'react'
|
|
||||||
import type LauncherManifest from '@/types/LauncherManifest'
|
|
||||||
|
|
||||||
type LauncherContextType = {
|
|
||||||
launcherManifest: LauncherManifest | null
|
|
||||||
}
|
|
||||||
|
|
||||||
const LauncherContext = createContext<LauncherContextType | null>(null)
|
|
||||||
|
|
||||||
export const useLauncher = () => useContext(LauncherContext)
|
|
||||||
|
|
||||||
export default LauncherContext
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { createContext, useContext } from 'react'
|
||||||
|
import type LauncherManifest from '@/types/LauncherManifest'
|
||||||
|
|
||||||
|
type GlobalProviderType = {
|
||||||
|
launcherManifest: LauncherManifest | null
|
||||||
|
}
|
||||||
|
|
||||||
|
const GlobalProvider = createContext<GlobalProviderType | null>(null)
|
||||||
|
|
||||||
|
export const useLauncher = () => useContext(GlobalProvider)
|
||||||
|
|
||||||
|
export default GlobalProvider
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {
|
||||||
|
createContext,
|
||||||
|
useContext,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
ReactNode
|
||||||
|
} from 'react'
|
||||||
|
import { load, Store } from '@tauri-apps/plugin-store'
|
||||||
|
|
||||||
|
type SettingsContextType = {
|
||||||
|
theme: string
|
||||||
|
notificationsAllowed: boolean
|
||||||
|
sidebarAlwaysShowGames: boolean
|
||||||
|
linuxUseWine: boolean
|
||||||
|
linuxWineCommand: string
|
||||||
|
settings: Store | null
|
||||||
|
}
|
||||||
|
|
||||||
|
const SettingsCtx = createContext<SettingsContextType | null>(null)
|
||||||
|
|
||||||
|
export const useSettings = () => {
|
||||||
|
const context = useContext(SettingsCtx)
|
||||||
|
if (!context) throw new Error('useSettings must be inside SettingsProvider')
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingsProvider ({ children }: { children: ReactNode }) {
|
||||||
|
const [theme, setThemeState] = useState('dark')
|
||||||
|
const [notificationsAllowed, setNotificationsAllowedState] = useState(false)
|
||||||
|
const [sidebarAlwaysShowGames, setSidebarAlwaysShowGamesState] =
|
||||||
|
useState(false)
|
||||||
|
const [linuxUseWine, setLinuxUseWineState] = useState(false)
|
||||||
|
const [linuxWineCommand, setLinuxWineCommandState] = useState('wine %path%')
|
||||||
|
const [store, setStore] = useState<Store | null>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
;(async () => {
|
||||||
|
const settingsStore = await load('settings.json', {
|
||||||
|
autoSave: true,
|
||||||
|
defaults: {
|
||||||
|
theme: 'dark',
|
||||||
|
notificationsAllowed: false,
|
||||||
|
sidebarAlwaysShowGames: false,
|
||||||
|
linuxUseWine: false,
|
||||||
|
linuxWineCommand: 'wine %path%'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setStore(settingsStore)
|
||||||
|
|
||||||
|
const themeValue = (await settingsStore.get('theme')) as string
|
||||||
|
const notificationsValue = (await settingsStore.get(
|
||||||
|
'notificationsAllowed'
|
||||||
|
)) as boolean
|
||||||
|
const sidebarValue = (await settingsStore.get(
|
||||||
|
'sidebarAlwaysShowGames'
|
||||||
|
)) as boolean
|
||||||
|
const wineValue = (await settingsStore.get('linuxUseWine')) as boolean
|
||||||
|
const wineCommandValue = (await settingsStore.get(
|
||||||
|
'linuxWineCommand'
|
||||||
|
)) as string
|
||||||
|
|
||||||
|
setThemeState(themeValue)
|
||||||
|
setNotificationsAllowedState(notificationsValue)
|
||||||
|
setSidebarAlwaysShowGamesState(sidebarValue)
|
||||||
|
setLinuxUseWineState(wineValue)
|
||||||
|
setLinuxWineCommandState(wineCommandValue)
|
||||||
|
|
||||||
|
settingsStore.onKeyChange('theme', (value: unknown) =>
|
||||||
|
setThemeState(value as string)
|
||||||
|
)
|
||||||
|
settingsStore.onKeyChange('notificationsAllowed', (value: unknown) =>
|
||||||
|
setNotificationsAllowedState(value as boolean)
|
||||||
|
)
|
||||||
|
settingsStore.onKeyChange('sidebarAlwaysShowGames', (value: unknown) =>
|
||||||
|
setSidebarAlwaysShowGamesState(value as boolean)
|
||||||
|
)
|
||||||
|
settingsStore.onKeyChange('linuxUseWine', (value: unknown) =>
|
||||||
|
setLinuxUseWineState(value as boolean)
|
||||||
|
)
|
||||||
|
settingsStore.onKeyChange('linuxWineCommand', (value: unknown) =>
|
||||||
|
setLinuxWineCommandState(value as string)
|
||||||
|
)
|
||||||
|
})()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsCtx.Provider
|
||||||
|
value={{
|
||||||
|
theme,
|
||||||
|
notificationsAllowed,
|
||||||
|
sidebarAlwaysShowGames,
|
||||||
|
linuxUseWine,
|
||||||
|
linuxWineCommand,
|
||||||
|
settings: store
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SettingsCtx.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -55,3 +55,23 @@ body {
|
|||||||
--col8: rgb(124, 112, 136);
|
--col8: rgb(124, 112, 136);
|
||||||
--col9: rgb(140, 128, 152);
|
--col9: rgb(140, 128, 152);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
@apply rounded-md cursor-pointer text-[16px] py-1 px-2 transition-colors border;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btntheme1 {
|
||||||
|
@apply bg-(--col2) border-(--col4) hover:bg-(--col4) hover:border-(--col6) disabled:text-gray-300 disabled:bg-(--col1) disabled:border-(--col5) disabled:hover:text-gray-100 disabled:hover:bg-(--col2) disabled:hover:border-(--col6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btntheme2,
|
||||||
|
.downloads-entry .entry-info-item,
|
||||||
|
.downloads-entry .button {
|
||||||
|
@apply bg-(--col3) border-(--col5) hover:bg-(--col5) hover:border-(--col7) disabled:text-gray-300 disabled:bg-(--col2) disabled:border-(--col6) disabled:hover:text-gray-100 disabled:hover:bg-(--col3) disabled:hover:border-(--col7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btntheme3,
|
||||||
|
.downloads-entry:hover .entry-info-item,
|
||||||
|
.downloads-entry:hover .button {
|
||||||
|
@apply bg-(--col4) border-(--col6) hover:bg-(--col6) hover:border-(--col8) disabled:text-gray-300 disabled:bg-(--col2) disabled:border-(--col7) disabled:hover:text-gray-100 disabled:hover:bg-(--col4) disabled:hover:border-(--col8);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
.setting-checkbox-wrapper {
|
||||||
|
@apply relative w-5 h-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-checkbox {
|
||||||
|
@apply appearance-none w-full h-full border-2 border-(--col4) rounded-md bg-(--col2) transition-colors cursor-pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-checkbox:checked {
|
||||||
|
@apply bg-(--col4) border-(--col6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-check-icon {
|
||||||
|
@apply absolute top-1/2 left-1/2 text-white text-[11px] pointer-events-none -translate-x-2/4 -translate-y-2/4;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export type SettingProps = {
|
||||||
|
label: string
|
||||||
|
value: boolean
|
||||||
|
onChange: (val: boolean) => void
|
||||||
|
className?: string
|
||||||
|
title?: string
|
||||||
|
}
|
||||||
Reference in new issue
Block a user