feat(config): split profile into Personal Info + Preferences sections, centered
All checks were successful
Beta Release / beta (push) Successful in 40s

- Profile panel now shows two distinct cards with section titles
- Personal Info (name, pseudo, email, languages) and Preferences
  (editor, shell, theme, etc.) are visually separated
- Content centered with max-width 540px
- Added i18n keys for section titles

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
Augustin
2026-04-23 21:29:07 +02:00
parent 6bad2948c5
commit 54621bd960
4 changed files with 43 additions and 24 deletions

View File

@@ -220,28 +220,47 @@ function PanelProfile({ config, editProfile, profileForm, setProfileForm, setEdi
if (!profile) {
return (
<div className="config-card">
<div className="empty-state">{t('config.loadingProfile')}</div>
<div className="config-profile-center">
<div className="config-card">
<div className="empty-state">{t('config.loadingProfile')}</div>
</div>
</div>
)
}
const personalKeys = Object.entries(profile).filter(([k, v]) => k !== 'preferences' && typeof v !== 'object')
const personalObj = Object.fromEntries(personalKeys)
const preferences = profile.preferences || null
return (
<div className="config-card">
<RenderFields obj={profile} path="" editing={editProfile} onChange={updateField} t={t} />
<div className="config-card-actions">
{editProfile ? (
<>
<button className="primary sm" onClick={handleSaveProfile}>{t('config.save')}</button>
<button className="ghost sm" onClick={() => setEditProfile(false)}>{t('config.cancel')}</button>
</>
<div className="config-profile-center">
<div className="config-card">
<div className="section-title">{t('config.profileInfo') || 'Informations personnelles'}</div>
<RenderFields obj={personalObj} path="" editing={editProfile} onChange={updateField} t={t} />
</div>
<div className="config-card">
<div className="section-title">{t('config.profilePrefs') || 'Préférences'}</div>
{preferences ? (
<RenderFields obj={preferences} path="preferences" editing={editProfile} onChange={updateField} t={t} />
) : (
<button className="primary sm" onClick={() => {
setProfileForm(config.profile ? JSON.parse(JSON.stringify(config.profile)) : {})
setEditProfile(true)
}}>{t('config.editProfile')}</button>
<div className="config-card-row"><span className="config-card-value" style={{ color: 'var(--text-disabled)' }}></span></div>
)}
</div>
<div className="config-card">
<div className="config-card-actions" style={{ justifyContent: 'center' }}>
{editProfile ? (
<>
<button className="primary sm" onClick={handleSaveProfile}>{t('config.save')}</button>
<button className="ghost sm" onClick={() => setEditProfile(false)}>{t('config.cancel')}</button>
</>
) : (
<button className="primary sm" onClick={() => {
setProfileForm(config.profile ? JSON.parse(JSON.stringify(config.profile)) : {})
setEditProfile(true)
}}>{t('config.editProfile')}</button>
)}
</div>
</div>
</div>
)
}
@@ -249,19 +268,10 @@ function PanelProfile({ config, editProfile, profileForm, setProfileForm, setEdi
function RenderFields({ obj, path, editing, onChange, t }) {
if (!obj || typeof obj !== 'object') return null
return Object.entries(obj).map(([key, value]) => {
return Object.entries(obj).filter(([, v]) => v === null || typeof v !== 'object').map(([key, value]) => {
const fieldPath = path ? `${path}.${key}` : key
const label = getFieldLabel(key, t)
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
return (
<div key={key} className="config-card-group">
<span className="config-card-group-label">{label}</span>
<RenderFields obj={value} path={fieldPath} editing={editing} onChange={onChange} t={t} />
</div>
)
}
if (editing) {
if (typeof value === 'boolean') {
return (

View File

@@ -182,6 +182,8 @@ const en = {
installed: 'Installed',
missing: 'Missing',
editProfile: 'Edit',
profileInfo: 'Personal Info',
profilePrefs: 'Preferences',
cancel: 'Cancel',
editProvider: 'Configure',
validateKey: 'Validate',

View File

@@ -182,6 +182,8 @@ const fr = {
installed: 'Install\u00e9',
missing: 'Manquant',
editProfile: 'Modifier',
profileInfo: 'Informations personnelles',
profilePrefs: 'Préférences',
editProvider: 'Configurer',
validateKey: 'Valider',
validating: 'V\u00e9rification...',

View File

@@ -435,6 +435,10 @@ input::placeholder { color: var(--text-disabled); }
.config-panel-area { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
.config-panel-body { flex: 1; overflow-y: auto; padding: 16px 28px 28px; }
.config-profile-center {
max-width: 540px; margin: 0 auto; width: 100%;
display: flex; flex-direction: column; gap: 12px;
}
.config-card {
background: var(--bg-card); border: 1px solid var(--border);
@@ -622,6 +626,7 @@ input::placeholder { color: var(--text-disabled); }
.dash-cmd-text {
font-size: 11px; font-family: var(--font-mono); color: var(--text-secondary);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
flex: 1; min-width: 0;
}
/* Services */