main #122

Merged
Patrick_Pluto merged 4 commits from sageTheDm/interstellar_ai:main into main 2024-10-09 08:19:16 +02:00
6 changed files with 100 additions and 117 deletions
Showing only changes of commit e0e711f1a9 - Show all commits

View file

@ -1,62 +1,24 @@
import React from 'react';
const Credits: React.FC = () => {
return (
<div className="credits-container">
<section id="credits" className="credits-section">
<h1 className="title">Credits</h1>
const Credits: React.FC = () => (
<div className="credits-container">
<section id="credits" className="credits-section">
<h1 className="title">Credits</h1>
<h2 className="subtitle">Icons</h2>
<p className="paragraph">This project utilizes the following icon resources:</p>
<CreditLink href="https://fontawesome.com/v4/license/" label="fontawesome" />
<h2 className="subtitle">Fonts</h2>
<p className="paragraph">The fonts used in this project are provided by:</p>
<CreditLink href="https://github.com/itfoundry/Poppins" label="Poppins" />
<CreditLink href="https://openfontlicense.org" label="Inconsolata, Merriweather, Noto Sans, Noto Serif, Playfair Display, Bangers, Caveat, Frederika the Great, Sofadi One, Zilla Slab Highlight" />
<CreditLink href="http://www.apache.org/licenses/LICENSE-2.0" label="Roboto, Rock Salt" />
<CreditLink href="https://ubuntu.com/legal/font-licence" label="Ubuntu" />
</section>
</div>
);
<h2 className="subtitle">Icons</h2>
<p className="paragraph">
This project utilizes the following icon resources:
</p>
<a
href="https://fontawesome.com/v4/license/"
className="credit-btn"
target="_blank"
rel="noopener noreferrer"
>
fontawesome
</a>
<h2 className="subtitle">Fonts</h2>
<p className="paragraph">
The fonts used in this project are provided by:
</p>
<a
href="https://github.com/itfoundry/Poppins"
className="credit-btn"
target="_blank"
rel="noopener noreferrer"
>
Poppins
</a>
<a
href="https://openfontlicense.org"
className="credit-btn"
target="_blank"
rel="noopener noreferrer"
>
Inconsolata, Merriweather, Noto Sans, Noto Serif, Playfair Display, Bangers, Caveat, Frederika the Great, Sofadi One, Zilla Slab Highlight
</a>
<a
href="http://www.apache.org/licenses/LICENSE-2.0"
className="credit-btn"
target="_blank"
rel="noopener noreferrer"
>
Roboto, Rock Salt
</a>
<a
href="https://ubuntu.com/legal/font-licence"
className="credit-btn"
target="_blank"
rel="noopener noreferrer"
>
Ubuntu
</a>
</section>
</div>
);
};
const CreditLink = ({ href, label }: { href: string; label: string }) => (
<a href={href} className="credit-btn" target="_blank" rel="noopener noreferrer">{label}</a>
);
export default Credits;

View file

@ -20,13 +20,16 @@ const Header: React.FC<HeaderProps> = ({
const dropdownRef = useRef<HTMLDivElement | null>(null);
const toggleRef = useRef<HTMLDivElement | null>(null);
// Pages that will be displayed in the menu
const pages: ('AI' | 'FAQ' | 'Documentation' | 'Credits')[] = ['AI', 'FAQ', 'Documentation', 'Credits'];
// Toggle menu state
const toggleMenu = () => {
setMenuOpen((prevMenuOpen) => !prevMenuOpen);
};
// Handle button click
const buttonClicked = (page: "AI" | "Documentation" | "FAQ" | "Credits") => {
const handleViewChange = (page: 'AI' | 'FAQ' | 'Documentation' | 'Credits') => {
onViewChange(page);
setMenuOpen(false); // Close the menu when a button is clicked
};
@ -35,9 +38,9 @@ const Header: React.FC<HeaderProps> = ({
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node) &&
toggleRef.current &&
toggleRef.current &&
!toggleRef.current.contains(event.target as Node)
) {
setMenuOpen(false);
@ -72,10 +75,11 @@ const Header: React.FC<HeaderProps> = ({
</button>
)}
<nav ref={dropdownRef} className={`nav-links ${menuOpen ? "active" : ""}`}>
<button onClick={() => buttonClicked("AI")} className="nav-btn">Chat</button>
<button onClick={() => buttonClicked("FAQ")} className="nav-btn">FAQ</button>
<button onClick={() => buttonClicked("Documentation")} className="nav-btn">Documentation</button>
<button onClick={() => buttonClicked("Credits")} className="nav-btn">Credits</button>
{pages.map(page => (
<button key={page} onClick={() => handleViewChange(page)} className="nav-btn">
{page}
</button>
))}
</nav>
<div ref={toggleRef} className={`hamburger ${menuOpen ? "open" : ""}`} onClick={toggleMenu}>
<span></span>

View file

@ -1,5 +1,5 @@
import React, { useState, ForwardedRef, useEffect } from 'react';
import "../styles/variables.css"
import "../styles/variables.css";
interface InputProps {
message: string;
@ -13,33 +13,36 @@ const InputFrontend = React.forwardRef<HTMLDivElement, InputProps>(
({ message, onSendClick, onMicClick, inputDisabled, isRecording }, ref: ForwardedRef<HTMLDivElement>) => {
const [inputValue, setInputValue] = useState('');
// Sync the inputValue state with the message prop
useEffect(() => {
setInputValue(message);
}, [message]);
// Handle the input change
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};
// Handle 'Enter' key press
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (!inputDisabled) {
if (event.key === 'Enter') {
onSendClick(inputValue, false); // Call the function passed via props
setInputValue(''); // Optionally clear input after submission
event.preventDefault(); // Prevent default action (e.g., form submission)
}
if (!inputDisabled && event.key === 'Enter') {
onSendClick(inputValue, false); // Send the message on Enter
setInputValue(''); // Clear the input after submission
event.preventDefault(); // Prevent the default Enter action
}
};
// Handle the Send button click
const handleSendClick = () => {
if (inputValue.trim() !== "") {
onSendClick(inputValue, false); // Send message to parent component
onSendClick(inputValue, false); // Send message
setInputValue(''); // Clear input after sending
}
};
return (
<div className="input" id="inputForm" ref={ref}>
{/* Input field for typing messages */}
<input
type="text"
name="user_message"
@ -47,13 +50,22 @@ const InputFrontend = React.forwardRef<HTMLDivElement, InputProps>(
value={inputValue}
onChange={handleInputChange}
onKeyDown={handleKeyDown}
className='textInputField'
className="textInputField"
disabled={inputDisabled} // Disable when inputDisabled is true
/>
<button type="button" onClick={handleSendClick} disabled={inputDisabled ? true : false}>
<svg style={{ fill: "var(--text-color)" }} viewBox="0 0 512 512" width={20}><path d="M498.1 5.6c10.1 7 15.4 19.1 13.5 31.2l-64 416c-1.5 9.7-7.4 18.2-16 23s-18.9 5.4-28 1.6L284 427.7l-68.5 74.1c-8.9 9.7-22.9 12.9-35.2 8.1S160 493.2 160 480l0-83.6c0-4 1.5-7.8 4.2-10.8L331.8 202.8c5.8-6.3 5.6-16-.4-22s-15.7-6.4-22-.7L106 360.8 17.7 316.6C7.1 311.3 .3 300.7 0 288.9s5.9-22.8 16.1-28.7l448-256c10.7-6.1 23.9-5.5 34 1.4z" /></svg>
{/* Send button */}
<button type="button" onClick={handleSendClick} disabled={inputDisabled}>
<svg style={{ fill: "var(--text-color)" }} viewBox="0 0 512 512" width={20}>
<path d="M498.1 5.6c10.1 7 15.4 19.1 13.5 31.2l-64 416c-1.5 9.7-7.4 18.2-16 23s-18.9 5.4-28 1.6L284 427.7l-68.5 74.1c-8.9 9.7-22.9 12.9-35.2 8.1S160 493.2 160 480l0-83.6c0-4 1.5-7.8 4.2-10.8L331.8 202.8c5.8-6.3 5.6-16-.4-22s-15.7-6.4-22-.7L106 360.8 17.7 316.6C7.1 311.3 .3 300.7 0 288.9s5.9-22.8 16.1-28.7l448-256c10.7-6.1 23.9-5.5 34 1.4z" />
</svg>
</button>
{/* Microphone button */}
<button className={`microphone-button ${isRecording ? "red" : "var(--input-button-color)"}`} type="button" onClick={onMicClick}>
<svg style={{ fill: "var(--text-color)" }} viewBox="0 0 384 512" width={15}><path d="M192 0C139 0 96 43 96 96l0 160c0 53 43 96 96 96s96-43 96-96l0-160c0-53-43-96-96-96zM64 216c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 40c0 89.1 66.2 162.7 152 174.4l0 33.6-48 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l72 0 72 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-48 0 0-33.6c85.8-11.7 152-85.3 152-174.4l0-40c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 40c0 70.7-57.3 128-128 128s-128-57.3-128-128l0-40z" /></svg>
<svg style={{ fill: "var(--text-color)" }} viewBox="0 0 384 512" width={15}>
<path d="M192 0C139 0 96 43 96 96l0 160c0 53 43 96 96 96s96-43 96-96l0-160c0-53-43-96-96-96zM64 216c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 40c0 89.1 66.2 162.7 152 174.4l0 33.6-48 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l72 0 72 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-48 0 0-33.6c85.8-11.7 152-85.3 152-174.4l0-40c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 40c0 70.7-57.3 128-128 128s-128-57.3-128-128l0-40z" />
</svg>
</button>
</div>
);

View file

@ -123,50 +123,39 @@ const ModelSection: React.FC = () => {
useEffect(() => {
if (typeof localStorage !== 'undefined') {
setIsOpenSourceMode(localStorage.getItem("openSourceMode"))
const temp = localStorage.getItem("activeSelectedAIFunction") || ""
setActiveSelectedAIFunction(temp)
if (!localStorage.getItem('selectedModelDropdown')) {
localStorage.setItem("selectedModelDropdown", "Offline Fast")
}
if (!localStorage.getItem("activeSelectedAIFunction")) {
setActiveSelectedAIFunction('Code')
localStorage.setItem('activeSelectedAIFunction', 'Code')
}
if (!localStorage.getItem("model")) {
localStorage.setItem("model", 'starcoder2')
}
if (!localStorage.getItem("radioSelection")) {
localStorage.setItem("radioSelection", 'None')
}
if (!localStorage.getItem("type")) {
localStorage.setItem("type", 'local')
}
const defaultValues = {
selectedModelDropdown: 'Offline Fast',
activeSelectedAIFunction: 'Code',
model: 'starcoder2',
radioSelection: 'None',
type: 'local',
};
Object.entries(defaultValues).forEach(([key, value]) => {
if (!localStorage.getItem(key)) {
localStorage.setItem(key, value);
}
});
setIsOpenSourceMode(localStorage.getItem("openSourceMode"));
setActiveSelectedAIFunction(localStorage.getItem("activeSelectedAIFunction") || '');
setRadioSelection(localStorage.getItem("radioSelection") || '');
setSelectedModelDropdown(localStorage.getItem('selectedModelDropdown') || '');
const handleStorageChange = () => {
setSelectedModelDropdown(localStorage.getItem('selectedModelDropdown') || '');
};
// Update immediately when localStorage changes
if (typeof window !== 'undefined') {
window.addEventListener('storage', handleStorageChange);
}
window.addEventListener('storage', handleStorageChange);
setRadioSelection(localStorage.getItem('radioSelection') || '');
setSelectedModelDropdown(localStorage.getItem('selectedModelDropdown') || '');
// Cleanup listener on component unmount
return () => {
if (typeof window !== 'undefined') {
window.removeEventListener('storage', handleStorageChange);
}
window.removeEventListener('storage', handleStorageChange);
};
}
}, []); // Dependency array can remain empty if you only want this to run on mount
}, []);
useEffect(() => {
if (typeof localStorage !== 'undefined') {
@ -271,7 +260,6 @@ const ModelSection: React.FC = () => {
))}
</select>
</div>
{/* Model Grid with Cards */}
<div className="grid">
{selectedAIFunction.map(

View file

@ -15,6 +15,7 @@ import {
changeSettings,
createAccount,
deleteAccount,
getSettings
} from '../../backend/database';
import ThemeDropdown from './DropDownTheme';
@ -298,6 +299,11 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
};
useEffect(() => {
let useName = localStorage.getItem("accountName")
let usePassword = localStorage.getItem("accountPassword")
if (useName && usePassword) {
importDatabase(useName, usePassword)
}
const savedTheme = localStorage.getItem('selectedTheme');
if (savedTheme) {
setSelectedTheme(savedTheme);
@ -305,6 +311,10 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
}
}, []); // Runs only once when the component mounts
const importDatabase = async (useName : string, usePassword : string) => {
const databaseSettings = await getSettings(useName, usePassword)
importSettings(databaseSettings)
}
// Effect hooks to update localStorage whenever any state changes
useEffect(() => {
// Flatten nested objects
@ -355,7 +365,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
}
if (await createAccount(useName, useEmail, usePassword)) {
if (await changeSettings(useName, usePassword, settings)) {
if (await changeSettings(useName, usePassword, handleExport)) {
localStorage.setItem("currentName", useName)
localStorage.setItem("currentPassword", usePassword)
localStorage.setItem("currentEmail", useEmail)
@ -714,7 +724,6 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
const handleExport = () => {
const settingsData = exportSettings();
// Create a blob and download the exported settings
const blob = new Blob([settingsData], { type: 'application/json' });
const url = URL.createObjectURL(blob);
@ -748,7 +757,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
<div className="settings-main">
{/* Dropdown for selections in responsive mode */}
<div className="settings-option dropdown">
<div className="dropdown-header"><h1>Select a Setting</h1></div>
<div className="dropdown-header"><h2>Select a Setting</h2></div>
<select onChange={(e) => setActiveSection(e.target.value)} value={activeSection}>
<option value="general">General</option>
<option value="privacy">Privacy</option>
@ -763,10 +772,13 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
{renderSettingsContent()}
<button className="close-popup" onClick={closeSettings}>Close</button>
<button className="apply" onClick={async () => {
// Your existing logic for applying settings
getAllLocalStorageItems();
closeSettings();
window.location.reload();
}}>
Apply
Apply
</button>
</div>
</div>
</div>

View file

@ -152,6 +152,11 @@
top: 10px;
display: block;
}
.slider-option{
width: fit-content;
margin: 10px 10px 0 0;
}
}
/* Responsive adjustments for the settings */