Some checks failed
Deploy to Production / deploy (push) Failing after 1m30s
- Updated all components with responsive breakpoints for mobile-first design - Added touch-friendly controls with proper spacing and small button sizes - Implemented responsive layouts that stack/wrap on mobile screens - Created detailed mobile compatibility documentation - Enhanced horizontal scrolling for data grids and steppers on mobile - Optimized media library grid for smaller screens - Added iOS safe area inset padding for bottom
146 lines
4.8 KiB
TypeScript
146 lines
4.8 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { Box, TextField, Button, Typography, Alert, Paper, Stack } from '@mui/material';
|
|
import { getSetting, updateSetting, resetSetting } from '../services/settings';
|
|
|
|
export default function Settings({ onBack }: { onBack?: () => void }) {
|
|
const [systemPrompt, setSystemPrompt] = useState('');
|
|
const [loading, setLoading] = useState(true);
|
|
const [saving, setSaving] = useState(false);
|
|
const [isDefault, setIsDefault] = useState(true);
|
|
const [message, setMessage] = useState<{ text: string; type: 'success' | 'error' } | null>(null);
|
|
|
|
useEffect(() => {
|
|
loadSystemPrompt();
|
|
}, []);
|
|
|
|
const loadSystemPrompt = async () => {
|
|
try {
|
|
setLoading(true);
|
|
const data = await getSetting('system_prompt');
|
|
setSystemPrompt(data.value);
|
|
setIsDefault(data.isDefault);
|
|
} catch (err: any) {
|
|
setMessage({ text: err?.message || 'Failed to load settings', type: 'error' });
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleSave = async () => {
|
|
try {
|
|
setSaving(true);
|
|
setMessage(null);
|
|
await updateSetting('system_prompt', systemPrompt);
|
|
setIsDefault(false);
|
|
setMessage({ text: 'System prompt saved successfully!', type: 'success' });
|
|
} catch (err: any) {
|
|
setMessage({ text: err?.message || 'Failed to save settings', type: 'error' });
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
const handleReset = async () => {
|
|
if (!confirm('Reset to default system prompt? This will delete your custom prompt.')) {
|
|
return;
|
|
}
|
|
try {
|
|
setSaving(true);
|
|
setMessage(null);
|
|
await resetSetting('system_prompt');
|
|
await loadSystemPrompt();
|
|
setMessage({ text: 'Reset to default system prompt', type: 'success' });
|
|
} catch (err: any) {
|
|
setMessage({ text: err?.message || 'Failed to reset settings', type: 'error' });
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<Box sx={{ p: 3 }}>
|
|
<Typography>Loading settings...</Typography>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Box sx={{ p: { xs: 2, md: 3 }, maxWidth: '1200px', margin: '0 auto' }}>
|
|
<Stack direction={{ xs: 'column', sm: 'row' }} justifyContent="space-between" alignItems={{ xs: 'stretch', sm: 'center' }} sx={{ mb: 3, gap: 1 }}>
|
|
<Typography variant="h4">Settings</Typography>
|
|
{onBack && (
|
|
<Button size="small" variant="outlined" onClick={onBack}>
|
|
Back to Posts
|
|
</Button>
|
|
)}
|
|
</Stack>
|
|
|
|
{message && (
|
|
<Alert severity={message.type} sx={{ mb: 2 }} onClose={() => setMessage(null)}>
|
|
{message.text}
|
|
</Alert>
|
|
)}
|
|
|
|
<Paper sx={{ p: 3 }}>
|
|
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
AI System Prompt
|
|
</Typography>
|
|
<Typography variant="body2" sx={{ mb: 2, color: 'text.secondary' }}>
|
|
This prompt defines how the AI generates article content. It controls the output format,
|
|
HTML structure, image placeholder format, and writing style.
|
|
{isDefault && (
|
|
<Typography component="span" sx={{ display: 'block', mt: 1, fontWeight: 'bold', color: 'info.main' }}>
|
|
Currently using default system prompt
|
|
</Typography>
|
|
)}
|
|
</Typography>
|
|
|
|
<TextField
|
|
label="System Prompt"
|
|
value={systemPrompt}
|
|
onChange={(e) => setSystemPrompt(e.target.value)}
|
|
fullWidth
|
|
multiline
|
|
minRows={15}
|
|
maxRows={30}
|
|
sx={{ mb: 2, fontFamily: 'monospace' }}
|
|
placeholder="Enter custom system prompt..."
|
|
/>
|
|
|
|
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
|
|
<Button
|
|
size="small"
|
|
variant="contained"
|
|
onClick={handleSave}
|
|
disabled={saving || !systemPrompt.trim()}
|
|
>
|
|
{saving ? 'Saving...' : 'Save Custom Prompt'}
|
|
</Button>
|
|
<Button
|
|
size="small"
|
|
variant="outlined"
|
|
onClick={handleReset}
|
|
disabled={saving || isDefault}
|
|
>
|
|
Reset to Default
|
|
</Button>
|
|
</Stack>
|
|
|
|
<Box sx={{ mt: 3, p: 2, bgcolor: 'grey.100', borderRadius: 1 }}>
|
|
<Typography variant="subtitle2" sx={{ mb: 1 }}>
|
|
💡 Tips for customizing the system prompt:
|
|
</Typography>
|
|
<Typography variant="body2" component="ul" sx={{ pl: 2 }}>
|
|
<li>Keep the image placeholder format: <code>{`{{IMAGE:description}}`}</code></li>
|
|
<li>Specify HTML tags to use (h2, h3, p, ul, ol, etc.)</li>
|
|
<li>Define the writing style and tone</li>
|
|
<li>Set content structure requirements</li>
|
|
<li>Add SEO or formatting guidelines</li>
|
|
</Typography>
|
|
</Box>
|
|
</Paper>
|
|
</Box>
|
|
);
|
|
}
|