feat: implement dashboard UI and configure path aliases for renderer and locales
This commit is contained in:
@@ -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()]
|
||||||
|
|||||||
+105
-62
@@ -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}
|
||||||
|
sx={{
|
||||||
|
p: 2.5,
|
||||||
|
background: 'rgba(255, 255, 255, 0.03)',
|
||||||
|
backdropFilter: 'blur(10px)',
|
||||||
|
border: '1px solid rgba(255, 255, 255, 0.05)',
|
||||||
|
borderRadius: 3,
|
||||||
|
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||||
|
'&:hover': {
|
||||||
|
background: 'rgba(255, 255, 255, 0.06)',
|
||||||
|
transform: 'translateY(-4px)',
|
||||||
|
borderColor: 'rgba(57, 167, 255, 0.3)',
|
||||||
|
boxShadow: '0 12px 24px rgba(0,0,0,0.3)'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', mb: 2 }}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
|
||||||
|
<Avatar sx={{ bgcolor: 'rgba(57, 167, 255, 0.1)', color: '#39A7FF' }}>
|
||||||
|
<FolderIcon />
|
||||||
|
</Avatar>
|
||||||
<Box>
|
<Box>
|
||||||
<IconButton edge="end" aria-label="edit" onClick={() => {
|
<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)
|
setNewProject(project)
|
||||||
setIsProjectDialogOpen(true)
|
setIsProjectDialogOpen(true)
|
||||||
}} sx={{ mr: 1 }}>
|
}} sx={{ color: 'rgba(255,255,255,0.4)', '&:hover': { color: '#39A7FF' } }}>
|
||||||
<EditIcon color="primary" />
|
<EditIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton edge="end" aria-label="delete" onClick={() => handleRemoveProject(project.id)}>
|
</Tooltip>
|
||||||
<DeleteIcon color="error" />
|
<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>
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
}
|
</Box>
|
||||||
>
|
|
||||||
<ListItemIcon><ProjectIcon color="primary" /></ListItemIcon>
|
<Stack spacing={1.5}>
|
||||||
<ListItemText
|
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||||
primary={project.name}
|
<Chip
|
||||||
secondary={`${project.path} - PHP: ${project.phpVersion} | MySQL: ${project.mySqlVersion || 'Yok'} - Host: ${project.host}`}
|
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)' }}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
{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>
|
</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 */}
|
|
||||||
<Dialog open={logDialogOpen} onClose={() => setLogDialogOpen(false)} fullWidth maxWidth="md">
|
|
||||||
<DialogTitle sx={{ bgcolor: '#1e1e1e', color: '#fff', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
||||||
<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>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
export default App
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"@renderer/*": [
|
"@renderer/*": [
|
||||||
"src/renderer/src/*"
|
"src/renderer/src/*"
|
||||||
|
],
|
||||||
|
"@locales/*": [
|
||||||
|
"src/renderer/src/locales/*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user