V0.9.21 branding updates
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jama-frontend",
|
||||
"version": "0.9.21",
|
||||
"version": "0.9.22",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -2,7 +2,8 @@ import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { api } from '../utils/api.js';
|
||||
import { useToast } from '../contexts/ToastContext.jsx';
|
||||
|
||||
const DEFAULT_TITLE_COLOR = '#1a73e8';
|
||||
const DEFAULT_TITLE_COLOR = '#1a73e8'; // light mode default
|
||||
const DEFAULT_TITLE_DARK_COLOR = '#60a5fa'; // dark mode default (lighter blue readable on dark bg)
|
||||
const DEFAULT_PUBLIC_COLOR = '#1a73e8';
|
||||
const DEFAULT_DM_COLOR = '#a142f4';
|
||||
|
||||
@@ -10,6 +11,45 @@ const COLOUR_SUGGESTIONS = [
|
||||
'#1a73e8', '#a142f4', '#e53935', '#fa7b17', '#fdd835', '#34a853',
|
||||
];
|
||||
|
||||
// ── Title Colour Row — one row per mode ──────────────────────────────────────
|
||||
|
||||
function TitleColourRow({ bgColor, bgLabel, textColor, appName, onChange }) {
|
||||
const [mode, setMode] = useState('idle'); // 'idle' | 'custom'
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||
{/* Preview box */}
|
||||
<div style={{
|
||||
background: bgColor, borderRadius: 8, padding: '0 14px',
|
||||
height: 44, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
border: '1px solid var(--border)', minWidth: 110, flexShrink: 0,
|
||||
boxShadow: '0 1px 4px rgba(0,0,0,0.1)',
|
||||
}}>
|
||||
<span style={{ color: textColor, fontWeight: 700, fontSize: 16, whiteSpace: 'nowrap' }}>
|
||||
{appName || 'ATC'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{mode === 'idle' && (
|
||||
<>
|
||||
<span style={{ fontSize: 12, color: 'var(--text-tertiary)', fontFamily: 'monospace', minWidth: 64 }}>{textColor}</span>
|
||||
<button className="btn btn-secondary btn-sm" onClick={() => setMode('custom')}>Custom</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{mode === 'custom' && (
|
||||
<div style={{ flex: 1 }}>
|
||||
<CustomPicker
|
||||
initial={textColor}
|
||||
onSet={(hex) => { onChange(hex); setMode('idle'); }}
|
||||
onBack={() => setMode('idle')}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ── Colour math helpers ──────────────────────────────────────────────────────
|
||||
|
||||
function hexToHsv(hex) {
|
||||
@@ -278,7 +318,8 @@ export default function BrandingModal({ onClose }) {
|
||||
const [resetting, setResetting] = useState(false);
|
||||
const [showResetConfirm, setShowResetConfirm] = useState(false);
|
||||
|
||||
const [colourTitle, setColourTitle] = useState(DEFAULT_TITLE_COLOR);
|
||||
const [colourTitle, setColourTitle] = useState(DEFAULT_TITLE_COLOR);
|
||||
const [colourTitleDark, setColourTitleDark] = useState(DEFAULT_TITLE_DARK_COLOR);
|
||||
const [colourPublic, setColourPublic] = useState(DEFAULT_PUBLIC_COLOR);
|
||||
const [colourDm, setColourDm] = useState(DEFAULT_DM_COLOR);
|
||||
const [savingColours, setSavingColours] = useState(false);
|
||||
@@ -288,6 +329,7 @@ export default function BrandingModal({ onClose }) {
|
||||
setSettings(settings);
|
||||
setAppName(settings.app_name || 'jama');
|
||||
setColourTitle(settings.color_title || DEFAULT_TITLE_COLOR);
|
||||
setColourTitleDark(settings.color_title_dark || DEFAULT_TITLE_DARK_COLOR);
|
||||
setColourPublic(settings.color_avatar_public || DEFAULT_PUBLIC_COLOR);
|
||||
setColourDm(settings.color_avatar_dm || DEFAULT_DM_COLOR);
|
||||
}).catch(() => {});
|
||||
@@ -329,12 +371,14 @@ export default function BrandingModal({ onClose }) {
|
||||
try {
|
||||
await api.updateColors({
|
||||
colorTitle: colourTitle,
|
||||
colorTitleDark: colourTitleDark,
|
||||
colorAvatarPublic: colourPublic,
|
||||
colorAvatarDm: colourDm,
|
||||
});
|
||||
setSettings(prev => ({
|
||||
...prev,
|
||||
color_title: colourTitle,
|
||||
color_title_dark: colourTitleDark,
|
||||
color_avatar_public: colourPublic,
|
||||
color_avatar_dm: colourDm,
|
||||
}));
|
||||
@@ -355,6 +399,7 @@ export default function BrandingModal({ onClose }) {
|
||||
setSettings(fresh);
|
||||
setAppName(fresh.app_name || 'jama');
|
||||
setColourTitle(DEFAULT_TITLE_COLOR);
|
||||
setColourTitleDark(DEFAULT_TITLE_DARK_COLOR);
|
||||
setColourPublic(DEFAULT_PUBLIC_COLOR);
|
||||
setColourDm(DEFAULT_DM_COLOR);
|
||||
toast('Settings reset to defaults', 'success');
|
||||
@@ -453,11 +498,25 @@ export default function BrandingModal({ onClose }) {
|
||||
|
||||
{tab === 'colours' && (
|
||||
<div className="flex-col gap-3">
|
||||
<ColourPicker
|
||||
label="App Title Colour"
|
||||
value={colourTitle}
|
||||
onChange={setColourTitle}
|
||||
/>
|
||||
<div>
|
||||
<div className="settings-section-label">App Title Colour</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 4 }}>
|
||||
<TitleColourRow
|
||||
bgColor="#f1f3f4"
|
||||
bgLabel="Light mode"
|
||||
textColor={colourTitle}
|
||||
appName={appName}
|
||||
onChange={setColourTitle}
|
||||
/>
|
||||
<TitleColourRow
|
||||
bgColor="#13131f"
|
||||
bgLabel="Dark mode"
|
||||
textColor={colourTitleDark}
|
||||
appName={appName}
|
||||
onChange={setColourTitleDark}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ borderTop: '1px solid var(--border)', paddingTop: 20 }}>
|
||||
<ColourPicker
|
||||
|
||||
@@ -5,17 +5,26 @@ import { api } from '../utils/api.js';
|
||||
export default function GlobalBar({ isMobile, showSidebar }) {
|
||||
const { connected } = useSocket();
|
||||
const [settings, setSettings] = useState({ app_name: 'jama', logo_url: '' });
|
||||
const [isDark, setIsDark] = useState(() => document.documentElement.getAttribute('data-theme') === 'dark');
|
||||
|
||||
useEffect(() => {
|
||||
api.getSettings().then(({ settings }) => setSettings(settings)).catch(() => {});
|
||||
const handler = () => api.getSettings().then(({ settings }) => setSettings(settings)).catch(() => {});
|
||||
window.addEventListener('jama:settings-changed', handler);
|
||||
return () => window.removeEventListener('jama:settings-changed', handler);
|
||||
// Re-render when theme changes so title colour switches correctly
|
||||
const themeObserver = new MutationObserver(() => {
|
||||
setIsDark(document.documentElement.getAttribute('data-theme') === 'dark');
|
||||
});
|
||||
themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
|
||||
return () => {
|
||||
window.removeEventListener('jama:settings-changed', handler);
|
||||
themeObserver.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const appName = settings.app_name || 'jama';
|
||||
const logoUrl = settings.logo_url;
|
||||
const titleColor = settings.color_title || null;
|
||||
const titleColor = (isDark ? settings.color_title_dark : settings.color_title) || null;
|
||||
|
||||
// On mobile: show bar only when sidebar is visible (chat list view)
|
||||
// On desktop: always show
|
||||
|
||||
Reference in New Issue
Block a user