forked from React-Group/interstellar_ai
Merge pull request 'main' (#37) from React-Group/interstellar_ai:main into main
Reviewed-on: https://interstellardevelopment.org/code/code/YasinOnm08/interstellar_ai/pulls/37
This commit is contained in:
commit
8c14760027
7 changed files with 898 additions and 1052 deletions
|
@ -3,7 +3,7 @@ import {
|
||||||
createAccount,
|
createAccount,
|
||||||
checkCredentials,
|
checkCredentials,
|
||||||
} from '../backend/database';
|
} from '../backend/database';
|
||||||
import Settings from './Settings'; // Import the Settings component
|
import Settings from './settings/Settings'; // Import the Settings component
|
||||||
|
|
||||||
const Login: React.FC = () => {
|
const Login: React.FC = () => {
|
||||||
// State to handle popup visibility
|
// State to handle popup visibility
|
||||||
|
|
File diff suppressed because it is too large
Load diff
29
app/components/settings/ColorSettings.tsx
Normal file
29
app/components/settings/ColorSettings.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface ColorSettingProps {
|
||||||
|
name: string; // The name to display in the <p> tag
|
||||||
|
value: string; // The current color value
|
||||||
|
setValue: (newColor: string) => void; // The method to update the state
|
||||||
|
cssVariable: string; // The CSS variable name to set
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColorSetting: React.FC<ColorSettingProps> = ({ name, value, setValue, cssVariable }) => {
|
||||||
|
const handleColorChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const newColor = e.target.value;
|
||||||
|
setValue(newColor);
|
||||||
|
document.documentElement.style.setProperty(cssVariable, newColor);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="settings-option">
|
||||||
|
<p>{name}</p>
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
value={value}
|
||||||
|
onChange={handleColorChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ColorSetting;
|
866
app/components/settings/Settings.tsx
Normal file
866
app/components/settings/Settings.tsx
Normal file
|
@ -0,0 +1,866 @@
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { applyTheme, applyCustomTheme } from './theme';
|
||||||
|
import { exportSettings, importSettings } from './settingUtils'; // Import utility functions
|
||||||
|
import { getAllLocalStorageItems } from '../../backend/GetLocalStorage';
|
||||||
|
import ColorSetting from './ColorSettings';
|
||||||
|
import {
|
||||||
|
changePassword,
|
||||||
|
changeData,
|
||||||
|
deleteAccount,
|
||||||
|
} from '../../backend/database';
|
||||||
|
|
||||||
|
|
||||||
|
const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = ({ closeSettings, accountName }) => {
|
||||||
|
|
||||||
|
const getItemFromLocalStorage = (key: string) => {
|
||||||
|
const item = localStorage.getItem(key);
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(item); // Attempt to parse the item
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Error parsing JSON for key "${key}":`, e);
|
||||||
|
return false; // Return false if parsing fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // Default to false if item is null or empty
|
||||||
|
};
|
||||||
|
|
||||||
|
interface SettingsProps {
|
||||||
|
closeSettings: () => void;
|
||||||
|
accountName: string;
|
||||||
|
handleLogout: () => void; // Add this line to accept handleLogout as a prop
|
||||||
|
}
|
||||||
|
|
||||||
|
// Active section
|
||||||
|
const [activeSection, setActiveSection] = useState(() => localStorage.getItem('activeSection') || 'general');
|
||||||
|
|
||||||
|
// Language setting
|
||||||
|
const [preferredLanguage, setPreferredLanguage] = useState(() => localStorage.getItem('preferredLanguage') || 'en');
|
||||||
|
|
||||||
|
// Currency setting
|
||||||
|
const [preferredCurrency, setPreferredCurrency] = useState(() => localStorage.getItem('preferredCurrency') || 'usd');
|
||||||
|
|
||||||
|
// Date and time format settings
|
||||||
|
const [dateFormat, setDateFormat] = useState(() => localStorage.getItem('dateFormat') || 'mm/dd/yyyy');
|
||||||
|
const [timeFormat, setTimeFormat] = useState(() => localStorage.getItem('timeFormat') || '12-hour');
|
||||||
|
const [timeZone, setTimeZone] = useState(() => localStorage.getItem('timeZone') || 'GMT');
|
||||||
|
|
||||||
|
// Online AI and chat history settings
|
||||||
|
const [selectedOption, setSelectedOption] = useState('Offline'); // Default to 'Offline'
|
||||||
|
const [disableChatHistory, setDisableChatHistory] = useState(() => getItemFromLocalStorage('disableChatHistory'));
|
||||||
|
const [disableAIMemory, setDisableAIMemory] = useState(() => getItemFromLocalStorage('disableAIMemory'));
|
||||||
|
const [openSourceMode, setOpenSourceMode] = useState(() => getItemFromLocalStorage('openSourceMode'));
|
||||||
|
|
||||||
|
// User credentials
|
||||||
|
const [newName, setNewName] = useState(() => localStorage.getItem('newName') || '');
|
||||||
|
const [newEmail, setNewEmail] = useState(() => localStorage.getItem('newEmail') || '');
|
||||||
|
const [newPassword, setNewPassword] = useState(() => localStorage.getItem('newPassword') || '');
|
||||||
|
const [currentPassword, setCurrentPassword] = useState('');
|
||||||
|
|
||||||
|
// Measurement setting
|
||||||
|
const [preferredMeasurement, setPreferredMeasurement] = useState(() => localStorage.getItem('preferredMeasurement') || 'Metric');
|
||||||
|
|
||||||
|
// Theme settings
|
||||||
|
const [backgroundColor, setBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--background-color').trim());
|
||||||
|
const [textColor, setTextColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--text-color').trim());
|
||||||
|
const [inputBackgroundColor, setInputBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--input-background-color').trim());
|
||||||
|
const [inputButtonColor, setInputButtonColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--input-button-color').trim());
|
||||||
|
const [inputButtonHoverColor, setInputButtonHoverColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--input-button-hover-color').trim());
|
||||||
|
const [userMessageBackgroundColor, setUserMessageBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--user-message-background-color').trim());
|
||||||
|
const [userMessageTextColor, setUserMessageTextColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--user-message-text-color').trim());
|
||||||
|
const [aiMessageBackgroundColor, setAiMessageBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--ai-message-background-color').trim());
|
||||||
|
const [aiMessageTextColor, setAiMessageTextColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--ai-message-text-color').trim());
|
||||||
|
const [buttonBackgroundColor, setButtonBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--button-background-color').trim());
|
||||||
|
const [buttonHoverBackgroundColor, setButtonHoverBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--button-hover-background-color').trim());
|
||||||
|
const [modelsBackgroundColor, setModelsBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--models-background-color').trim());
|
||||||
|
const [historyBackgroundColor, setHistoryBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--history-background-color').trim());
|
||||||
|
const [leftPanelBackgroundColor, setLeftPanelBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--left-panel-background-color').trim());
|
||||||
|
const [conversationBackgroundColor, setConversationBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--conversation-background-color').trim());
|
||||||
|
const [popUpTextColor, setPopUpTextColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--pop-up-text').trim());
|
||||||
|
const [inputBorderColor, setInputBorderColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--input-border-color').trim());
|
||||||
|
const [fontFamily, setFontFamily] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--font-family').trim());
|
||||||
|
const [fontSize, setFontSize] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--font-size').trim());
|
||||||
|
const [burgerMenu, setBurgerMenu] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--burger-menu-background-color').trim());
|
||||||
|
const [faqBackgroundColor, setFaqBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--faq-background-color').trim());
|
||||||
|
const [faqHeadingColor, setFaqHeadingColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--faq-heading-color').trim());
|
||||||
|
const [faqItemBackgroundColor, setFaqItemBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--faq-item-background-color').trim());
|
||||||
|
const [faqItemHeadingColor, setFaqItemHeadingColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--faq-item-heading-color').trim());
|
||||||
|
const [faqItemTextColor, setFaqItemTextColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--faq-item-text-color').trim());
|
||||||
|
const [faqItemHoverBackgroundColor, setFaqItemHoverBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--faq-item-hover-background-color').trim());
|
||||||
|
const [popupBackgroundColor, setPopupBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--popup-background-color').trim());
|
||||||
|
const [overlayTextColor, setOverlayTextColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--overlay-text-color').trim());
|
||||||
|
|
||||||
|
|
||||||
|
// Theme selection
|
||||||
|
const [selectedTheme, setSelectedTheme] = useState<string>('');
|
||||||
|
|
||||||
|
// API Keys
|
||||||
|
const [mistral, setmistral] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--online-la-plateforme').trim());
|
||||||
|
const [openai, setopenai] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--online-cheap-openai').trim());
|
||||||
|
const [anthropic, setAnthropic] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--online-cheap-anthropic').trim());
|
||||||
|
const [google, setGoogle] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--online-cheap-google').trim());
|
||||||
|
|
||||||
|
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||||
|
|
||||||
|
const settings = {
|
||||||
|
userPreferences: {
|
||||||
|
activeSection,
|
||||||
|
preferredLanguage,
|
||||||
|
preferredCurrency,
|
||||||
|
dateFormat,
|
||||||
|
timeFormat,
|
||||||
|
timeZone,
|
||||||
|
selectedOption,
|
||||||
|
disableChatHistory,
|
||||||
|
disableAIMemory,
|
||||||
|
openSourceMode,
|
||||||
|
newName,
|
||||||
|
newEmail,
|
||||||
|
newPassword,
|
||||||
|
preferredMeasurement,
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
backgroundColor,
|
||||||
|
textColor,
|
||||||
|
inputBackgroundColor,
|
||||||
|
inputButtonColor,
|
||||||
|
inputButtonHoverColor,
|
||||||
|
userMessageBackgroundColor,
|
||||||
|
userMessageTextColor,
|
||||||
|
aiMessageBackgroundColor,
|
||||||
|
aiMessageTextColor,
|
||||||
|
buttonBackgroundColor,
|
||||||
|
buttonHoverBackgroundColor,
|
||||||
|
modelsBackgroundColor,
|
||||||
|
historyBackgroundColor,
|
||||||
|
leftPanelBackgroundColor,
|
||||||
|
conversationBackgroundColor,
|
||||||
|
popUpTextColor,
|
||||||
|
inputBorderColor,
|
||||||
|
fontFamily,
|
||||||
|
fontSize,
|
||||||
|
selectedTheme,
|
||||||
|
faqSettings: {
|
||||||
|
faqBackgroundColor,
|
||||||
|
faqHeadingColor,
|
||||||
|
faqItemBackgroundColor,
|
||||||
|
faqItemHeadingColor,
|
||||||
|
faqItemTextColor,
|
||||||
|
faqItemHoverBackgroundColor,
|
||||||
|
},
|
||||||
|
popupSettings: {
|
||||||
|
popupBackgroundColor,
|
||||||
|
overlayTextColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
apiKeys: {
|
||||||
|
mistral,
|
||||||
|
openai,
|
||||||
|
anthropic,
|
||||||
|
google,
|
||||||
|
},
|
||||||
|
generalSettings: {
|
||||||
|
burgerMenu,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
setIsLoggedIn(false);
|
||||||
|
localStorage.removeItem('accountName');
|
||||||
|
localStorage.removeItem('accountEmail');
|
||||||
|
localStorage.removeItem('accountPassword');
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const savedTheme = localStorage.getItem('selectedTheme');
|
||||||
|
if (savedTheme) {
|
||||||
|
setSelectedTheme(savedTheme);
|
||||||
|
applyTheme(savedTheme);
|
||||||
|
}
|
||||||
|
}, []); // Runs only once when the component mounts
|
||||||
|
|
||||||
|
// Effect hooks to update localStorage whenever any state changes
|
||||||
|
useEffect(() => {
|
||||||
|
// Flatten nested objects
|
||||||
|
const flattenedSettings = {
|
||||||
|
...settings.userPreferences,
|
||||||
|
...settings.theme,
|
||||||
|
...settings.theme.faqSettings,
|
||||||
|
...settings.theme.popupSettings,
|
||||||
|
...settings.apiKeys,
|
||||||
|
...settings.generalSettings,
|
||||||
|
};
|
||||||
|
// Update localStorage for all settings
|
||||||
|
for (const [key, value] of Object.entries(flattenedSettings)) {
|
||||||
|
localStorage.setItem(key, typeof value === 'boolean' ? JSON.stringify(value) : value);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
...Object.values(settings.userPreferences),
|
||||||
|
...Object.values(settings.theme),
|
||||||
|
...Object.values(settings.theme.faqSettings),
|
||||||
|
...Object.values(settings.theme.popupSettings),
|
||||||
|
...Object.values(settings.apiKeys),
|
||||||
|
...Object.values(settings.generalSettings),
|
||||||
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const savedOption = localStorage.getItem('radioSelection');
|
||||||
|
if (savedOption) {
|
||||||
|
setSelectedOption(savedOption); // Set saved selection
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleRadioChange = (newValue: string) => {
|
||||||
|
setSelectedOption(newValue); // Update the state with the selected option
|
||||||
|
if (openSourceMode){
|
||||||
|
newValue += " (FOSS)"
|
||||||
|
}
|
||||||
|
localStorage.setItem('radioSelection', newValue); // Save the selection for persistence
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to handle updating all credentials
|
||||||
|
const handleUpdateCredentials = async () => {
|
||||||
|
// Update account information
|
||||||
|
const newData = {
|
||||||
|
name: newName || accountName, // Keep old name if new name is not provided
|
||||||
|
email: newEmail || '', // Optionally use empty string if not provided
|
||||||
|
};
|
||||||
|
|
||||||
|
// First change the data
|
||||||
|
const dataSuccess = await changeData(accountName, currentPassword, newData);
|
||||||
|
|
||||||
|
// Then change the password if a new password is provided
|
||||||
|
const passwordSuccess = newPassword ?
|
||||||
|
await changePassword(accountName, currentPassword, newPassword) :
|
||||||
|
true; // If no new password, treat as success
|
||||||
|
|
||||||
|
if (dataSuccess && passwordSuccess) {
|
||||||
|
alert('Credentials updated successfully!');
|
||||||
|
closeSettings(); // Close settings after updating
|
||||||
|
} else {
|
||||||
|
alert('Failed to update credentials. Please check your current password.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to handle account deletion
|
||||||
|
const handleDeleteAccount = async () => {
|
||||||
|
const success = await deleteAccount(accountName, currentPassword);
|
||||||
|
if (success) {
|
||||||
|
alert('Account deleted successfully!');
|
||||||
|
closeSettings(); // Close settings after deletion
|
||||||
|
// Optionally, redirect or reset state here
|
||||||
|
} else {
|
||||||
|
alert('Account deletion failed. Please check your password.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Render settings content based on the active section
|
||||||
|
const renderSettingsContent = () => {
|
||||||
|
switch (activeSection) {
|
||||||
|
case 'general':
|
||||||
|
return (
|
||||||
|
<div className="settings-section">
|
||||||
|
<h2>General Settings</h2>
|
||||||
|
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>Preferred Language</label>
|
||||||
|
<select
|
||||||
|
value={preferredLanguage}
|
||||||
|
onChange={(e) => setPreferredLanguage(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="en">English</option>
|
||||||
|
<option value="es">Spanish</option>
|
||||||
|
<option value="fr">French</option>
|
||||||
|
<option value="de">German</option>
|
||||||
|
<option value="it">Italian</option>
|
||||||
|
<option value="pt">Portuguese</option>
|
||||||
|
<option value="zh">Chinese</option>
|
||||||
|
<option value="ja">Japanese</option>
|
||||||
|
<option value="ru">Russian</option>
|
||||||
|
<option value="ar">Arabic</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>Preferred Currency</label>
|
||||||
|
<select
|
||||||
|
value={preferredCurrency}
|
||||||
|
onChange={(e) => setPreferredCurrency(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="usd">USD</option>
|
||||||
|
<option value="eur">EUR</option>
|
||||||
|
<option value="gbp">GBP</option>
|
||||||
|
<option value="jpy">JPY</option>
|
||||||
|
<option value="cad">CAD</option>
|
||||||
|
<option value="aud">AUD</option>
|
||||||
|
<option value="chf">CHF</option>
|
||||||
|
<option value="cny">CNY</option>
|
||||||
|
<option value="inr">INR</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>Date Format</label>
|
||||||
|
<select
|
||||||
|
value={dateFormat}
|
||||||
|
onChange={(e) => setDateFormat(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="mm/dd/yyyy">MM/DD/YYYY</option>
|
||||||
|
<option value="dd/mm/yyyy">DD/MM/YYYY</option>
|
||||||
|
<option value="yyyy-mm-dd">YYYY-MM-DD</option>
|
||||||
|
<option value="mm-dd-yyyy">MM-DD-YYYY</option>
|
||||||
|
<option value="dd-mm-yyyy">DD-MM-YYYY</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>Time Format</label>
|
||||||
|
<select
|
||||||
|
value={timeFormat}
|
||||||
|
onChange={(e) => setTimeFormat(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="12-hour">12 Hour</option>
|
||||||
|
<option value="24-hour">24 Hour</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>Time Zone</label>
|
||||||
|
<select
|
||||||
|
value={timeZone}
|
||||||
|
onChange={(e) => setTimeZone(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="GMT">GMT</option>
|
||||||
|
<option value="EST">EST</option>
|
||||||
|
<option value="CST">CST</option>
|
||||||
|
<option value="MST">MST</option>
|
||||||
|
<option value="PST">PST</option>
|
||||||
|
<option value="UTC">UTC</option>
|
||||||
|
<option value="BST">BST</option>
|
||||||
|
<option value="IST">IST</option>
|
||||||
|
<option value="CET">CET</option>
|
||||||
|
<option value="JST">JST</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* New Preferred Measurement Option */}
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>Preferred Measurement</label>
|
||||||
|
<select
|
||||||
|
value={preferredMeasurement}
|
||||||
|
onChange={(e) => setPreferredMeasurement(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="Metric">Metric</option>
|
||||||
|
<option value="Imperial">Imperial</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
case 'privacy':
|
||||||
|
return (
|
||||||
|
<div className="settings-section">
|
||||||
|
<h2>Privacy Settings</h2>
|
||||||
|
{/* AI Mode Radio Options */}
|
||||||
|
<div className="settings-option">
|
||||||
|
<p>Disable Options:</p>
|
||||||
|
<div className="slider">
|
||||||
|
{/* Offline */}
|
||||||
|
<div
|
||||||
|
className={`slider-option ${selectedOption === 'Offline' ? 'active' : ''}`}
|
||||||
|
onClick={() => handleRadioChange('Offline')} // Allow selection only if not in open-source mode
|
||||||
|
>
|
||||||
|
Offline tools{openSourceMode ? ' (FOSS)' : ''}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Online */}
|
||||||
|
<div
|
||||||
|
className={`slider-option ${selectedOption === 'Online' ? 'active' : ''}`}
|
||||||
|
onClick={() => handleRadioChange('Online')}
|
||||||
|
>
|
||||||
|
Online tools{openSourceMode ? ' (FOSS)' : ''}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* None */}
|
||||||
|
<div
|
||||||
|
className={`slider-option ${selectedOption === 'None' ? 'active' : ''}`}
|
||||||
|
onClick={() => handleRadioChange('None')}
|
||||||
|
>
|
||||||
|
None{openSourceMode ? ' (FOSS)' : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
After changing the preferred settings, please reload the website so it can update itself properly.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Disable Chat History Checkbox */}
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={disableChatHistory}
|
||||||
|
onChange={() => setDisableChatHistory(!disableChatHistory)}
|
||||||
|
/>
|
||||||
|
Disable Chat History
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Disable AI Memory Checkbox */}
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={disableAIMemory}
|
||||||
|
onChange={() => setDisableAIMemory(!disableAIMemory)}
|
||||||
|
/>
|
||||||
|
Disable AI Memory
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
case 'theme':
|
||||||
|
return (
|
||||||
|
<div className="settings-section">
|
||||||
|
<h2>Theme Settings</h2>
|
||||||
|
|
||||||
|
{/* Dropdown to select theme */}
|
||||||
|
<div className="settings-option">
|
||||||
|
<p>Select Theme</p>
|
||||||
|
<select
|
||||||
|
value={selectedTheme}
|
||||||
|
onChange={(e) => {
|
||||||
|
const theme = e.target.value;
|
||||||
|
if (theme !== "default") {
|
||||||
|
setSelectedTheme(theme);
|
||||||
|
localStorage.setItem("selectedTheme", theme);
|
||||||
|
|
||||||
|
// Apply the appropriate theme based on selection
|
||||||
|
applyTheme(theme);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="default">Select your style...</option>
|
||||||
|
<option value="IOMARKET">IOMARKET</option>
|
||||||
|
<option value="WHITE">WHITE</option>
|
||||||
|
<option value="BLACK">BLACK</option>
|
||||||
|
<option value="CUSTOM">CUSTOM</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{/* Conditionally render theme settings only if "CUSTOM" is selected */}
|
||||||
|
{selectedTheme === 'CUSTOM' && (
|
||||||
|
<>
|
||||||
|
{/* Font Size */}
|
||||||
|
<div className="settings-option">
|
||||||
|
<p>Font Size</p>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min="12"
|
||||||
|
max="30"
|
||||||
|
value={parseInt(fontSize, 10)} // Ensure value is a number
|
||||||
|
onChange={(e) => {
|
||||||
|
const newSize = `${e.target.value}px`;
|
||||||
|
setFontSize(newSize);
|
||||||
|
document.documentElement.style.setProperty('--font-size', newSize);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span>{fontSize}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ColorSetting
|
||||||
|
name="Background Color"
|
||||||
|
value={backgroundColor}
|
||||||
|
setValue={setBackgroundColor}
|
||||||
|
cssVariable="--background-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="Text Color"
|
||||||
|
value={textColor}
|
||||||
|
setValue={setTextColor}
|
||||||
|
cssVariable="--text-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="Input Background Color"
|
||||||
|
value={inputBackgroundColor}
|
||||||
|
setValue={setInputBackgroundColor}
|
||||||
|
cssVariable="--input-background-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="Input Button Color"
|
||||||
|
value={inputButtonColor}
|
||||||
|
setValue={setInputButtonColor}
|
||||||
|
cssVariable="--input-button-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="Input Button Hover Color"
|
||||||
|
value={inputButtonHoverColor}
|
||||||
|
setValue={setInputButtonHoverColor}
|
||||||
|
cssVariable="--input-button-hover-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="User Message Background Color"
|
||||||
|
value={userMessageBackgroundColor}
|
||||||
|
setValue={setUserMessageBackgroundColor}
|
||||||
|
cssVariable="--user-message-background-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="User Message Text Color"
|
||||||
|
value={userMessageTextColor}
|
||||||
|
setValue={setUserMessageTextColor}
|
||||||
|
cssVariable="--user-message-text-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="AI Message Background Color"
|
||||||
|
value={aiMessageBackgroundColor}
|
||||||
|
setValue={setAiMessageBackgroundColor}
|
||||||
|
cssVariable="--ai-message-background-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="AI Message Text Color"
|
||||||
|
value={aiMessageTextColor}
|
||||||
|
setValue={setAiMessageTextColor}
|
||||||
|
cssVariable="--ai-message-text-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="Button Background Color"
|
||||||
|
value={buttonBackgroundColor}
|
||||||
|
setValue={setButtonBackgroundColor}
|
||||||
|
cssVariable="--button-background-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="Button Hover Background Color"
|
||||||
|
value={buttonHoverBackgroundColor}
|
||||||
|
setValue={setButtonHoverBackgroundColor}
|
||||||
|
cssVariable="--button-hover-background-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="Models Background Color"
|
||||||
|
value={modelsBackgroundColor}
|
||||||
|
setValue={setModelsBackgroundColor}
|
||||||
|
cssVariable="--models-background-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="History Background Color"
|
||||||
|
value={historyBackgroundColor}
|
||||||
|
setValue={setHistoryBackgroundColor}
|
||||||
|
cssVariable="--history-background-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="Left Panel Background Color"
|
||||||
|
value={leftPanelBackgroundColor}
|
||||||
|
setValue={setLeftPanelBackgroundColor}
|
||||||
|
cssVariable="--left-panel-background-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="Conversation Background Color"
|
||||||
|
value={conversationBackgroundColor}
|
||||||
|
setValue={setConversationBackgroundColor}
|
||||||
|
cssVariable="--conversation-background-color"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="Pop-up Text Color"
|
||||||
|
value={popUpTextColor}
|
||||||
|
setValue={setPopUpTextColor}
|
||||||
|
cssVariable="--pop-up-text"
|
||||||
|
/>
|
||||||
|
<ColorSetting
|
||||||
|
name="Input Border Color"
|
||||||
|
value={inputBorderColor}
|
||||||
|
setValue={setInputBorderColor}
|
||||||
|
cssVariable="--input-border-color"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ColorSetting
|
||||||
|
name="FAQ Background Color"
|
||||||
|
value={faqBackgroundColor}
|
||||||
|
setValue={setFaqBackgroundColor}
|
||||||
|
cssVariable="--faq-background-color"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ColorSetting
|
||||||
|
name="FAQ Heading Color"
|
||||||
|
value={faqHeadingColor}
|
||||||
|
setValue={setFaqHeadingColor}
|
||||||
|
cssVariable="--faq-heading-color"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ColorSetting
|
||||||
|
name="FAQ Item Background Color"
|
||||||
|
value={faqItemBackgroundColor}
|
||||||
|
setValue={setFaqItemBackgroundColor}
|
||||||
|
cssVariable="--faq-item-background-color"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ColorSetting
|
||||||
|
name="FAQ Item Heading Color"
|
||||||
|
value={faqItemHeadingColor}
|
||||||
|
setValue={setFaqItemHeadingColor}
|
||||||
|
cssVariable="--faq-item-heading-color"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ColorSetting
|
||||||
|
name="FAQ Item Text Color"
|
||||||
|
value={faqItemTextColor}
|
||||||
|
setValue={setFaqItemTextColor}
|
||||||
|
cssVariable="--faq-item-text-color"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ColorSetting
|
||||||
|
name="FAQ Item Hover Background Color"
|
||||||
|
value={faqItemHoverBackgroundColor}
|
||||||
|
setValue={setFaqItemHoverBackgroundColor}
|
||||||
|
cssVariable="--faq-item-hover-background-color"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ColorSetting
|
||||||
|
name="Popup Background Color"
|
||||||
|
value={popupBackgroundColor}
|
||||||
|
setValue={setPopupBackgroundColor}
|
||||||
|
cssVariable="--popup-background-color"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ColorSetting
|
||||||
|
name="Overlay Text Color"
|
||||||
|
value={overlayTextColor}
|
||||||
|
setValue={setOverlayTextColor}
|
||||||
|
cssVariable="--overlay-text-color"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="settings-option">
|
||||||
|
<p>Font Family</p>
|
||||||
|
<select
|
||||||
|
value={fontFamily}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newFont = e.target.value;
|
||||||
|
setFontFamily(newFont);
|
||||||
|
document.documentElement.style.setProperty('--font-family', newFont);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="'Poppins', sans-serif">Poppins</option>
|
||||||
|
<option value="'Inconsolata', monospace">Inconsolata</option>
|
||||||
|
<option value="'Merriweather', serif">Merriweather</option>
|
||||||
|
<option value="'Noto Sans', sans-serif">Noto Sans</option>
|
||||||
|
<option value="'Noto Serif', serif">Noto Serif</option>
|
||||||
|
<option value="'Playfair Display', serif">Playfair Display</option>
|
||||||
|
<option value="'Roboto', sans-serif">Roboto</option>
|
||||||
|
<option value="'Ubuntu', sans-serif">Ubuntu</option>
|
||||||
|
<option value="'Bangers', cursive">Bangers</option>
|
||||||
|
<option value="'Caveat', cursive">Caveat</option>
|
||||||
|
<option value="'Frederika the Great', cursive">Frederika the Great</option>
|
||||||
|
<option value="'Rock Salt', cursive">Rock Salt</option>
|
||||||
|
<option value="'Sofadi One', sans-serif">Sofadi One</option>
|
||||||
|
<option value="'Zilla Slab Highlight', serif">Zilla Slab Highlight</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
case 'foss':
|
||||||
|
return (
|
||||||
|
<div className="settings-section">
|
||||||
|
<h2>Open Source Settings</h2>
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={openSourceMode}
|
||||||
|
onChange={() => {
|
||||||
|
const newValue = !openSourceMode;
|
||||||
|
setOpenSourceMode(newValue);
|
||||||
|
// Update radio selection based on the new openSourceMode value
|
||||||
|
if (newValue) {
|
||||||
|
setSelectedOption('FOSS'); // Set to FOSS if enabling open source mode
|
||||||
|
} else {
|
||||||
|
setSelectedOption('None'); // Or any other default value when disabling
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
Enable Open Source Mode
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
case 'account':
|
||||||
|
return (
|
||||||
|
<div className="settings-section">
|
||||||
|
<h2>Account Settings</h2>
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>New Name</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={newName}
|
||||||
|
onChange={(e) => setNewName(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>New Email</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
value={newEmail}
|
||||||
|
onChange={(e) => setNewEmail(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>New Password</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
value={newPassword}
|
||||||
|
onChange={(e) => setNewPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>Current Password</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
value={currentPassword}
|
||||||
|
onChange={(e) => setCurrentPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="settings-option">
|
||||||
|
<button
|
||||||
|
onClick={handleLogout} // Update all credentials
|
||||||
|
className="update-credentials-button"
|
||||||
|
>
|
||||||
|
Log Out
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="settings-option">
|
||||||
|
<button
|
||||||
|
onClick={handleUpdateCredentials} // Update all credentials
|
||||||
|
className="update-credentials-button"
|
||||||
|
>
|
||||||
|
Update Credentials
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="settings-option">
|
||||||
|
<button
|
||||||
|
onClick={handleDeleteAccount} // Delete account
|
||||||
|
className="delete-account-button"
|
||||||
|
>
|
||||||
|
Delete Account
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
case 'api':
|
||||||
|
return (
|
||||||
|
<div className="settings-section">
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>La Plateforme</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={mistral}
|
||||||
|
onChange={(e) => setmistral(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>OpenAI</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={openai}
|
||||||
|
onChange={(e) => setopenai(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>Anthropic</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={anthropic}
|
||||||
|
onChange={(e) => setAnthropic(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="settings-option">
|
||||||
|
<label>Google</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={google}
|
||||||
|
onChange={(e) => setGoogle(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
case 'im/export':
|
||||||
|
return (
|
||||||
|
<div className="settings-section">
|
||||||
|
<h2>Import & Export</h2>
|
||||||
|
<div className="settings-option">
|
||||||
|
<h3>Export the settings</h3>
|
||||||
|
<button onClick={() => exportSettings(currentSettings)} className='export-button'>Export Settings</button>
|
||||||
|
</div>
|
||||||
|
<div className="settings-option">
|
||||||
|
<h3>Import the settings</h3>
|
||||||
|
<input type="file" onChange={handleImport} accept=".json" className='import-file'/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle file import
|
||||||
|
const handleImport = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (event.target.files && event.target.files.length > 0) {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
importSettings(file, applyCustomTheme);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gather all settings into an object
|
||||||
|
// Gather current settings into an object
|
||||||
|
const currentSettings = {
|
||||||
|
...settings.userPreferences,
|
||||||
|
...settings.theme,
|
||||||
|
...settings.theme.faqSettings,
|
||||||
|
...settings.theme.popupSettings,
|
||||||
|
...settings.apiKeys,
|
||||||
|
...settings.generalSettings,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="popup-overlay">
|
||||||
|
<div className="settings-content">
|
||||||
|
<div className="settings-container">
|
||||||
|
<div className="sidebar">
|
||||||
|
<ul>
|
||||||
|
<li onClick={() => setActiveSection('general')}>General</li>
|
||||||
|
<li onClick={() => setActiveSection('privacy')}>Privacy</li>
|
||||||
|
<li onClick={() => setActiveSection('theme')}>Theme</li>
|
||||||
|
<li onClick={() => setActiveSection('foss')}>FOSS</li>
|
||||||
|
<li onClick={() => setActiveSection('account')}>Account</li>
|
||||||
|
<li onClick={() => setActiveSection('api')}>API Keys</li>
|
||||||
|
<li onClick={() => setActiveSection('im/export')}>Import/Export</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div className="settings-main">
|
||||||
|
<h2>Settings for {accountName}</h2>
|
||||||
|
{renderSettingsContent()}
|
||||||
|
<button className="close-popup" onClick={closeSettings}>Close</button>
|
||||||
|
<button className="apply" onClick={() => {
|
||||||
|
getAllLocalStorageItems();
|
||||||
|
closeSettings();
|
||||||
|
}}>
|
||||||
|
Apply
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Settings;
|
|
@ -7,8 +7,8 @@ import Documentation from './components/Documentation'; // Ensure the import pat
|
||||||
import History from './components/History';
|
import History from './components/History';
|
||||||
import Models from './components/Models';
|
import Models from './components/Models';
|
||||||
import Credits from './components/Credits';
|
import Credits from './components/Credits';
|
||||||
import Settings from './components/Settings';
|
import Settings from './components/settings/Settings';
|
||||||
import { applyIOMarketTheme, applyWhiteTheme, applyBlackTheme, applyCustomTheme } from './components/theme'
|
import { applyIOMarketTheme, applyWhiteTheme, applyBlackTheme, applyCustomTheme } from './components/settings/theme'
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import './styles/master.css';
|
import './styles/master.css';
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue