settings dialog

This commit is contained in:
Novattz
2025-06-24 19:45:29 +02:00
parent 41dba65879
commit 1ac1931a08
7 changed files with 293 additions and 3 deletions

View File

@@ -8,7 +8,7 @@ import { Header, Sidebar, InitialLoadingScreen, ErrorBoundary } from '@/componen
import AnimatedBackground from '@/components/layout/AnimatedBackground' import AnimatedBackground from '@/components/layout/AnimatedBackground'
// Dialog components // Dialog components
import { ProgressDialog, DlcSelectionDialog } from '@/components/dialogs' import { ProgressDialog, DlcSelectionDialog, SettingsDialog } from '@/components/dialogs'
// Game components // Game components
import { GameList } from '@/components/games' import { GameList } from '@/components/games'
@@ -40,6 +40,9 @@ function App() {
handleGameAction, handleGameAction,
handleDlcConfirm, handleDlcConfirm,
handleGameEdit, handleGameEdit,
settingsDialog,
handleSettingsOpen,
handleSettingsClose,
} = useAppContext() } = useAppContext()
// Show loading screen during initial load // Show loading screen during initial load
@@ -63,7 +66,7 @@ function App() {
<div className="main-content"> <div className="main-content">
{/* Sidebar for filtering */} {/* Sidebar for filtering */}
<Sidebar setFilter={setFilter} currentFilter={filter} /> <Sidebar setFilter={setFilter} currentFilter={filter} onSettingsClick={handleSettingsOpen} />
{/* Show error or game list */} {/* Show error or game list */}
{error ? ( {error ? (
@@ -105,6 +108,12 @@ function App() {
onClose={handleDlcDialogClose} onClose={handleDlcDialogClose}
onConfirm={handleDlcConfirm} onConfirm={handleDlcConfirm}
/> />
{/* Settings Dialog */}
<SettingsDialog
visible ={settingsDialog.visible}
onClose={handleSettingsClose}
/>
{/* Simple update notifier that uses toast - no UI component */} {/* Simple update notifier that uses toast - no UI component */}
<UpdateNotifier /> <UpdateNotifier />

View File

@@ -0,0 +1,95 @@
import React from 'react'
import {
Dialog,
DialogHeader,
DialogBody,
DialogFooter,
DialogActions,
} from '@/components/dialogs'
import { Button } from '@/components/buttons'
import { Icon, settings } from '@/components/icons'
interface SettingsDialogProps {
visible: boolean
onClose: () => void
}
/**
* Settings Dialog component
* Contains application settings and configuration options
*/
const SettingsDialog: React.FC<SettingsDialogProps> = ({ visible, onClose }) => {
return (
<Dialog visible={visible} onClose={onClose} size="medium">
<DialogHeader onClose={onClose} hideCloseButton={true}>
<div className="settings-header">
<Icon name={settings} variant="bold" size="md" />
<h3>Settings</h3>
</div>
</DialogHeader>
<DialogBody>
<div className="settings-content">
<div className="settings-section">
<h4>General Settings</h4>
<p className="settings-description">
Configure your CreamLinux preferences and application behavior.
</p>
<div className="settings-placeholder">
<div className="placeholder-icon"> <Icon name={settings} variant="bold" size="xl" /> </div>
<div className="placeholder-text">
<h5>Settings Coming Soon</h5>
<p>
Working on adding customizable settings to improve your experience.
Future options may include:
</p>
<ul>
<li>Custom Steam library paths</li>
<li>Automatic update settings</li>
<li>Scan frequency options</li>
<li>DLC catalog</li>
</ul>
</div>
</div>
</div>
<div className="settings-section">
<h4>About CreamLinux</h4>
<div className="app-info">
<div className="info-row">
<span className="info-label">Version:</span>
<span className="info-value">1.0.2</span>
</div>
<div className="info-row">
<span className="info-label">Build:</span>
<span className="info-value">Beta</span>
</div>
<div className="info-row">
<span className="info-label">Repository:</span>
<a
href="https://github.com/Novattz/creamlinux-installer"
target="_blank"
rel="noopener noreferrer"
className="info-link"
>
GitHub
</a>
</div>
</div>
</div>
</div>
</DialogBody>
<DialogFooter>
<DialogActions>
<Button variant="secondary" onClick={onClose}>
Close
</Button>
</DialogActions>
</DialogFooter>
</Dialog>
)
}
export default SettingsDialog

View File

@@ -6,6 +6,7 @@ export { default as DialogFooter } from './DialogFooter'
export { default as DialogActions } from './DialogActions' export { default as DialogActions } from './DialogActions'
export { default as ProgressDialog } from './ProgressDialog' export { default as ProgressDialog } from './ProgressDialog'
export { default as DlcSelectionDialog } from './DlcSelectionDialog' export { default as DlcSelectionDialog } from './DlcSelectionDialog'
export { default as SettingsDialog } from './SettingsDialog'
// Export types // Export types
export type { DialogProps } from './Dialog' export type { DialogProps } from './Dialog'

View File

@@ -49,6 +49,11 @@ export interface AppContextType {
handleGameAction: (gameId: string, action: ActionType) => Promise<void> handleGameAction: (gameId: string, action: ActionType) => Promise<void>
handleDlcConfirm: (selectedDlcs: DlcInfo[]) => void handleDlcConfirm: (selectedDlcs: DlcInfo[]) => void
// Settings
settingsDialog: { visible: boolean }
handleSettingsOpen: () => void
handleSettingsClose: () => void
// Toast notifications // Toast notifications
showToast: ( showToast: (
message: string, message: string,

View File

@@ -1,4 +1,4 @@
import { ReactNode } from 'react' import { ReactNode, useState } from 'react'
import { AppContext, AppContextType } from './AppContext' import { AppContext, AppContextType } from './AppContext'
import { useGames, useDlcManager, useGameActions, useToasts } from '@/hooks' import { useGames, useDlcManager, useGameActions, useToasts } from '@/hooks'
import { DlcInfo } from '@/types' import { DlcInfo } from '@/types'
@@ -35,6 +35,18 @@ export const AppProvider = ({ children }: AppProviderProps) => {
const { toasts, removeToast, success, error: showError, warning, info } = useToasts() const { toasts, removeToast, success, error: showError, warning, info } = useToasts()
// Settings dialog state
const [settingsDialog, setSettingsDialog] = useState({ visible: false })
// Settings handlers
const handleSettingsOpen = () => {
setSettingsDialog({ visible: true })
}
const handleSettingsClose = () => {
setSettingsDialog({ visible: false })
}
// Game action handler with proper error reporting // Game action handler with proper error reporting
const handleGameAction = async (gameId: string, action: ActionType) => { const handleGameAction = async (gameId: string, action: ActionType) => {
const game = games.find((g) => g.id === gameId) const game = games.find((g) => g.id === gameId)
@@ -180,6 +192,11 @@ export const AppProvider = ({ children }: AppProviderProps) => {
handleDlcConfirm, handleDlcConfirm,
handleProgressDialogClose: handleCloseProgressDialog, handleProgressDialogClose: handleCloseProgressDialog,
// Settings
settingsDialog,
handleSettingsOpen,
handleSettingsClose,
// Toast notifications // Toast notifications
showToast, showToast,
} }

View File

@@ -1,3 +1,4 @@
@forward './dialog'; @forward './dialog';
@forward './dlc_dialog'; @forward './dlc_dialog';
@forward './progress_dialog'; @forward './progress_dialog';
@forward './settings_dialog';

View File

@@ -0,0 +1,162 @@
@use '../../themes/index' as *;
@use '../../abstracts/index' as *;
/*
Settings dialog styles
*/
.settings-header {
display: flex;
gap: 0.75rem;
}
.settings-content {
display: flex;
flex-direction: column;
gap: 2rem;
}
.settings-section {
h4 {
font-size: 1.1rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 0.5rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--border-soft);
}
.settings-description {
color: var(--text-secondary);
font-size: 0.9rem;
margin-bottom: 1.5rem;
line-height: 1.4;
}
}
.settings-placeholder {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 2rem;
background-color: var(--border-dark);
border-radius: var(--radius-md);
border: 1px solid var(--border-soft);
.placeholder-icon {
font-size: 3rem;
margin-bottom: 1rem;
opacity: 0.7;
}
.placeholder-text {
h5 {
font-size: 1.1rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 0.75rem;
}
p {
color: var(--text-secondary);
font-size: 0.9rem;
line-height: 1.4;
margin-bottom: 1rem;
}
ul {
text-align: left;
color: var(--text-soft);
font-size: 0.85rem;
line-height: 1.6;
max-width: 300px;
li {
margin-bottom: 0.25rem;
&::before {
content: '';
color: var(--primary-color);
margin-right: 0.5rem;
}
}
}
}
}
.app-info {
background-color: var(--border-dark);
border-radius: var(--radius-sm);
padding: 1rem;
border: 1px solid var(--border-soft);
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem 0;
&:not(:last-child) {
border-bottom: 1px solid var(--border-soft);
}
.info-label {
font-weight: 500;
color: var(--text-secondary);
font-size: 0.9rem;
}
.info-value {
color: var(--text-primary);
font-size: 0.9rem;
font-family: monospace;
}
.info-link {
color: var(--primary-color);
text-decoration: none;
font-size: 0.9rem;
transition: color 0.2s ease;
&:hover {
color: var(--secondary-color);
text-decoration: underline;
}
}
}
}
// Settings button in sidebar
.settings-button {
margin-top: auto;
padding: 0.75rem 1rem;
border-radius: var(--radius-sm);
transition: all var(--duration-normal) var(--easing-ease-out);
cursor: pointer;
display: flex;
align-items: center;
gap: 0.75rem;
color: var(--text-secondary);
font-weight: 500;
border: 1px solid transparent;
&:hover {
background-color: rgba(255, 255, 255, 0.05);
color: var(--text-primary);
border-color: var(--border-soft);
}
&:active {
transform: scale(0.98);
}
.settings-icon {
flex-shrink: 0;
transition: transform 0.3s ease;
}
&:hover .settings-icon {
transform: rotate(45deg);
}
}