feat: implement dashboard UI and configure path aliases for renderer and locales

This commit is contained in:
Ümit Tunç
2026-03-28 20:48:05 +03:00
parent ab037b7bd9
commit f9c9bf117e
7 changed files with 124 additions and 78 deletions
+2 -2
View File
@@ -12,8 +12,8 @@ export default defineConfig({
renderer: { renderer: {
resolve: { resolve: {
alias: { alias: {
'@renderer': resolve('src/renderer/src'), '@renderer': resolve(__dirname, 'src/renderer/src'),
'@locales': resolve('locales') '@locales': resolve(__dirname, 'src/renderer/src/locales')
} }
}, },
plugins: [react()] plugins: [react()]
+116 -73
View File
@@ -34,7 +34,9 @@ import {
Tab, Tab,
InputAdornment, InputAdornment,
CircularProgress, CircularProgress,
Stack Stack,
Grid,
Avatar
} from '@mui/material' } from '@mui/material'
import { import {
Dashboard as DashboardIcon, Dashboard as DashboardIcon,
@@ -55,11 +57,14 @@ import {
Save as SaveIcon, Save as SaveIcon,
LanguageOutlined as WebIcon, LanguageOutlined as WebIcon,
Terminal as TerminalIcon, Terminal as TerminalIcon,
ContentCopy as CopyIcon,
Close as CloseIcon, Close as CloseIcon,
ContentCopy as ContentCopyIcon, ContentCopy as ContentCopyIcon,
OpenInNew as OpenIcon, OpenInNew as OpenIcon,
Edit as EditIcon Edit as EditIcon,
Folder as FolderIcon,
Storage as MySQLIcon,
Language as HostIcon,
Launch as LaunchIcon
} from '@mui/icons-material' } from '@mui/icons-material'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@@ -810,33 +815,110 @@ function App(): JSX.Element {
<Typography variant="body1" color="text.secondary">Henüz bir proje eklenmemiş.</Typography> <Typography variant="body1" color="text.secondary">Henüz bir proje eklenmemiş.</Typography>
</Paper> </Paper>
) : ( ) : (
<List> <Grid container spacing={3}>
{projects.map((project) => ( {projects.map((project) => (
<Paper key={project.id} sx={{ mb: 2, bgcolor: 'rgba(255, 255, 255, 0.05)' }}> <Grid item xs={12} md={6} key={project.id}>
<ListItem <Paper
secondaryAction={ elevation={0}
<Box> sx={{
<IconButton edge="end" aria-label="edit" onClick={() => { p: 2.5,
setNewProject(project) background: 'rgba(255, 255, 255, 0.03)',
setIsProjectDialogOpen(true) backdropFilter: 'blur(10px)',
}} sx={{ mr: 1 }}> border: '1px solid rgba(255, 255, 255, 0.05)',
<EditIcon color="primary" /> borderRadius: 3,
</IconButton> transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
<IconButton edge="end" aria-label="delete" onClick={() => handleRemoveProject(project.id)}> '&:hover': {
<DeleteIcon color="error" /> background: 'rgba(255, 255, 255, 0.06)',
</IconButton> transform: 'translateY(-4px)',
</Box> borderColor: 'rgba(57, 167, 255, 0.3)',
} boxShadow: '0 12px 24px rgba(0,0,0,0.3)'
}
}}
> >
<ListItemIcon><ProjectIcon color="primary" /></ListItemIcon> <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', mb: 2 }}>
<ListItemText <Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
primary={project.name} <Avatar sx={{ bgcolor: 'rgba(57, 167, 255, 0.1)', color: '#39A7FF' }}>
secondary={`${project.path} - PHP: ${project.phpVersion} | MySQL: ${project.mySqlVersion || 'Yok'} - Host: ${project.host}`} <FolderIcon />
/> </Avatar>
</ListItem> <Box>
</Paper> <Typography variant="h6" sx={{ fontWeight: 700, color: '#fff', lineHeight: 1.2 }}>
{project.name}
</Typography>
<Typography variant="caption" sx={{ color: 'rgba(255, 255, 255, 0.4)', fontFamily: 'monospace' }}>
{project.path.length > 40 ? '...' + project.path.slice(-37) : project.path}
</Typography>
</Box>
</Box>
<Box sx={{ display: 'flex', gap: 0.5 }}>
<Tooltip title="Düzenle">
<IconButton size="small" onClick={() => {
setNewProject(project)
setIsProjectDialogOpen(true)
}} sx={{ color: 'rgba(255,255,255,0.4)', '&:hover': { color: '#39A7FF' } }}>
<EditIcon fontSize="small" />
</IconButton>
</Tooltip>
<Tooltip title="Sil">
<IconButton size="small" onClick={() => handleRemoveProject(project.id)} sx={{ color: 'rgba(255,255,255,0.4)', '&:hover': { color: '#ff4444' } }}>
<DeleteIcon fontSize="small" />
</IconButton>
</Tooltip>
</Box>
</Box>
<Stack spacing={1.5}>
<Box sx={{ display: 'flex', gap: 1 }}>
<Chip
size="small"
icon={<PhpIcon sx={{ fontSize: '1rem !important' }} />}
label={`PHP ${project.phpVersion}`}
sx={{ bgcolor: 'rgba(71, 74, 255, 0.1)', color: '#777bb4', fontWeight: 600, border: '1px solid rgba(71, 74, 255, 0.2)' }}
/>
{project.mySqlVersion && (
<Chip
size="small"
icon={<MySQLIcon sx={{ fontSize: '1rem !important' }} />}
label={`MySQL ${project.mySqlVersion}`}
sx={{ bgcolor: 'rgba(242, 145, 17, 0.1)', color: '#f29111', fontWeight: 600, border: '1px solid rgba(242, 145, 17, 0.2)' }}
/>
)}
</Box>
<Paper variant="outlined" sx={{
p: 1.5,
bgcolor: 'rgba(0,0,0,0.2)',
borderColor: 'rgba(255,255,255,0.05)',
borderRadius: 2,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between'
}}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<HostIcon sx={{ fontSize: '1rem', color: 'rgba(255,255,255,0.3)' }} />
<Typography variant="body2" sx={{ color: '#fff', fontWeight: 500, fontFamily: 'monospace' }}>
{project.host}
</Typography>
</Box>
<Button
size="small"
endIcon={<LaunchIcon />}
onClick={() => window.open(`http://${project.host}`, '_blank')}
sx={{
color: '#39A7FF',
textTransform: 'none',
fontSize: '0.75rem',
p: '2px 8px',
'&:hover': { bgcolor: 'rgba(57, 167, 255, 0.1)' }
}}
>
Gözat
</Button>
</Paper>
</Stack>
</Paper>
</Grid>
))} ))}
</List> </Grid>
)} )}
</Box> </Box>
)} )}
@@ -1046,51 +1128,12 @@ function App(): JSX.Element {
variant="contained" variant="contained"
disabled={!newProject.name || !newProject.path || installedPhpVersions.length === 0 || mySqlVersions.filter(v => v.status === 'installed').length === 0} disabled={!newProject.name || !newProject.path || installedPhpVersions.length === 0 || mySqlVersions.filter(v => v.status === 'installed').length === 0}
> >
</Dialog> {newProject.id ? 'Güncelle' : 'Ekle'}
</Button>
{/* Log Dialog */} </DialogActions>
<Dialog open={logDialogOpen} onClose={() => setLogDialogOpen(false)} fullWidth maxWidth="md"> </Dialog>
<DialogTitle sx={{ bgcolor: '#1e1e1e', color: '#fff', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> </Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}> )
<TerminalIcon />
{selectedService.toUpperCase()} Konsol Çıktısı
</Box>
<Box>
<IconButton size="small" sx={{ color: '#fff' }} onClick={() => navigator.clipboard.writeText(logs.join('\n'))}>
<CopyIcon fontSize="small" />
</IconButton>
</Box>
</DialogTitle>
<DialogContent sx={{ bgcolor: '#000', p: 0 }}>
<Box
sx={{
p: 2,
fontFamily: 'Consolas, monospace',
fontSize: '0.85rem',
color: '#00ff00',
height: '400px',
overflowY: 'auto',
display: 'flex',
flexDirection: 'column'
}}
>
{logs.length === 0 ? (
<Typography variant="caption" sx={{ color: '#666' }}>Henüz log kaydı yok...</Typography>
) : (
logs.map((line, i) => (
<Box key={i} sx={{ mb: 0.5, borderLeft: '2px solid #333', pl: 1 }}>
{line}
</Box>
))
)}
</Box>
</DialogContent>
<DialogActions sx={{ bgcolor: '#1e1e1e' }}>
<Button onClick={() => setLogDialogOpen(false)} variant="contained" size="small">Kapat</Button>
</DialogActions>
</Dialog>
</Box>
)
} }
export default App export default App
+3 -3
View File
@@ -1,8 +1,8 @@
import i18n from 'i18next' import i18n from 'i18next'
import { initReactI18next } from 'react-i18next' import { initReactI18next } from 'react-i18next'
import tr from '@locales/tr.json' import tr from './locales/tr.json'
import en from '@locales/en.json' import en from './locales/en.json'
import de from '@locales/de.json' import de from './locales/de.json'
i18n i18n
.use(initReactI18next) .use(initReactI18next)
+3
View File
@@ -13,6 +13,9 @@
"paths": { "paths": {
"@renderer/*": [ "@renderer/*": [
"src/renderer/src/*" "src/renderer/src/*"
],
"@locales/*": [
"src/renderer/src/locales/*"
] ]
} }
} }