mirror of
https://github.com/ItzCrazyKns/Perplexica.git
synced 2025-10-21 14:58:15 +00:00
feat(app): fix sizes & placement for smaller screens
This commit is contained in:
@@ -78,7 +78,7 @@ const ModelProvider = ({
|
||||
)}
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
<p className="text-black dark:text-white font-medium">
|
||||
<p className="text-sm lg:text-base text-black dark:text-white font-medium">
|
||||
{modelProvider.name}
|
||||
</p>
|
||||
<div className="flex items-center gap-4">
|
||||
@@ -115,7 +115,7 @@ const ModelProvider = ({
|
||||
{modelProvider.chatModels.length > 0 && (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
<div className="flex flex-row w-full justify-between items-center">
|
||||
<p className="text-xs text-black/70 dark:text-white/70">
|
||||
<p className="text-[11px] lg:text-xs text-black/70 dark:text-white/70">
|
||||
Chat models
|
||||
</p>
|
||||
<AddModel
|
||||
@@ -126,7 +126,7 @@ const ModelProvider = ({
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
{modelProvider.chatModels.some((m) => m.key === 'error') ? (
|
||||
<div className="flex flex-row items-center gap-2 text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30">
|
||||
<div className="flex flex-row items-center gap-2 text-xs lg:text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30">
|
||||
<AlertCircle size={16} className="shrink-0" />
|
||||
<span className="break-words">
|
||||
{
|
||||
@@ -141,7 +141,7 @@ const ModelProvider = ({
|
||||
{modelProvider.chatModels.map((model, index) => (
|
||||
<div
|
||||
key={`${modelProvider.id}-chat-${model.key}-${index}`}
|
||||
className="flex flex-row items-center space-x-1 text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
|
||||
className="flex flex-row items-center space-x-1 text-xs lg:text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
|
||||
>
|
||||
<span>{model.name}</span>
|
||||
<button
|
||||
@@ -161,7 +161,7 @@ const ModelProvider = ({
|
||||
{modelProvider.embeddingModels.length > 0 && (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
<div className="flex flex-row w-full justify-between items-center">
|
||||
<p className="text-xs text-black/70 dark:text-white/70">
|
||||
<p className="text-[11px] lg:text-xs text-black/70 dark:text-white/70">
|
||||
Embedding models
|
||||
</p>
|
||||
<AddModel
|
||||
@@ -174,7 +174,7 @@ const ModelProvider = ({
|
||||
{modelProvider.embeddingModels.some(
|
||||
(m) => m.key === 'error',
|
||||
) ? (
|
||||
<div className="flex flex-row items-center gap-2 text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30">
|
||||
<div className="flex flex-row items-center gap-2 text-xs lg:text-sm text-red-500 dark:text-red-400 rounded-lg bg-red-50 dark:bg-red-950/20 px-3 py-2 border border-red-200 dark:border-red-900/30">
|
||||
<AlertCircle size={16} className="shrink-0" />
|
||||
<span className="break-words">
|
||||
{
|
||||
@@ -189,7 +189,7 @@ const ModelProvider = ({
|
||||
{modelProvider.embeddingModels.map((model, index) => (
|
||||
<div
|
||||
key={`${modelProvider.id}-embedding-${model.key}-${index}`}
|
||||
className="flex flex-row items-center space-x-1 text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
|
||||
className="flex flex-row items-center space-x-1 text-xs lg:text-sm text-black/70 dark:text-white/70 rounded-lg bg-light-secondary dark:bg-dark-secondary px-3 py-1.5"
|
||||
>
|
||||
<span>{model.name}</span>
|
||||
<button
|
||||
|
@@ -18,16 +18,23 @@ const ModelSelect = ({
|
||||
const handleSave = async (newValue: string) => {
|
||||
setLoading(true);
|
||||
setSelectedModel(newValue);
|
||||
console.log(newValue);
|
||||
try {
|
||||
if (type === 'chat') {
|
||||
localStorage.setItem('chatModelProviderId', newValue.split('/')[0]);
|
||||
localStorage.setItem('chatModelKey', newValue.split('/')[1]);
|
||||
localStorage.setItem(
|
||||
'chatModelKey',
|
||||
newValue.split('/').slice(1).join('/'),
|
||||
);
|
||||
} else {
|
||||
localStorage.setItem(
|
||||
'embeddingModelProviderId',
|
||||
newValue.split('/')[0],
|
||||
);
|
||||
localStorage.setItem('embeddingModelKey', newValue.split('/')[1]);
|
||||
localStorage.setItem(
|
||||
'embeddingModelKey',
|
||||
newValue.split('/').slice(1).join('/'),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error saving config:', error);
|
||||
@@ -38,13 +45,13 @@ const ModelSelect = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="rounded-xl border border-light-200 bg-light-primary/80 p-6 transition-colors dark:border-dark-200 dark:bg-dark-primary/80">
|
||||
<div className="space-y-5">
|
||||
<section className="rounded-xl border border-light-200 bg-light-primary/80 p-4 lg:p-6 transition-colors dark:border-dark-200 dark:bg-dark-primary/80">
|
||||
<div className="space-y-3 lg:space-y-5">
|
||||
<div>
|
||||
<h4 className="text-base text-black dark:text-white">
|
||||
<h4 className="text-sm lg:text-base text-black dark:text-white">
|
||||
Select {type === 'chat' ? 'Chat Model' : 'Embedding Model'}
|
||||
</h4>
|
||||
<p className="text-xs text-black/50 dark:text-white/50">
|
||||
<p className="text-[11px] lg:text-xs text-black/50 dark:text-white/50">
|
||||
{type === 'chat'
|
||||
? 'Select the model to use for chat responses'
|
||||
: 'Select the model to use for embeddings'}
|
||||
@@ -68,7 +75,7 @@ const ModelSelect = ({
|
||||
})),
|
||||
)
|
||||
}
|
||||
className="w-full rounded-lg border border-light-200 dark:border-dark-200 bg-light-primary dark:bg-dark-primary px-4 py-3 text-sm text-black/80 dark:text-white/80 placeholder:text-black/40 dark:placeholder:text-white/40 focus-visible:outline-none focus-visible:border-light-300 dark:focus-visible:border-dark-300 transition-colors disabled:cursor-not-allowed disabled:opacity-60 cursor-pointer capitalize pr-12"
|
||||
className="!text-xs lg:!text-sm"
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
/>
|
||||
|
@@ -1,5 +1,11 @@
|
||||
import { Dialog, DialogPanel } from '@headlessui/react';
|
||||
import { BrainCog, ChevronLeft, Search, Settings } from 'lucide-react';
|
||||
import {
|
||||
ArrowLeft,
|
||||
BrainCog,
|
||||
ChevronLeft,
|
||||
Search,
|
||||
Settings,
|
||||
} from 'lucide-react';
|
||||
import General from './Sections/General';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -8,9 +14,11 @@ import Loader from '../ui/Loader';
|
||||
import { cn } from '@/lib/utils';
|
||||
import Models from './Sections/Models/Section';
|
||||
import SearchSection from './Sections/Search';
|
||||
import Select from '@/components/ui/Select';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
key: 'general',
|
||||
name: 'General',
|
||||
description: 'Adjust common settings.',
|
||||
icon: Settings,
|
||||
@@ -18,6 +26,7 @@ const sections = [
|
||||
dataAdd: 'general',
|
||||
},
|
||||
{
|
||||
key: 'models',
|
||||
name: 'Models',
|
||||
description: 'Configure model settings.',
|
||||
icon: BrainCog,
|
||||
@@ -25,6 +34,7 @@ const sections = [
|
||||
dataAdd: 'modelProviders',
|
||||
},
|
||||
{
|
||||
key: 'search',
|
||||
name: 'Search',
|
||||
description: 'Manage search settings.',
|
||||
icon: Search,
|
||||
@@ -42,7 +52,12 @@ const SettingsDialogue = ({
|
||||
}) => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [config, setConfig] = useState<any>(null);
|
||||
const [activeSection, setActiveSection] = useState(sections[0]);
|
||||
const [activeSection, setActiveSection] = useState<string>(sections[0].key);
|
||||
const [selectedSection, setSelectedSection] = useState(sections[0]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedSection(sections.find((s) => s.key === activeSection)!);
|
||||
}, [activeSection]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
@@ -83,14 +98,14 @@ const SettingsDialogue = ({
|
||||
transition={{ duration: 0.1 }}
|
||||
className="fixed inset-0 flex w-screen items-center justify-center p-4 bg-black/30 backdrop-blur-sm h-screen"
|
||||
>
|
||||
<DialogPanel className="space-y-4 border border-light-200 dark:border-dark-200 bg-light-primary dark:bg-dark-primary backdrop-blur-lg rounded-xl h-[calc(100vh-2%)] w-[calc(100vw-2%)] md:h-[calc(100vh-7%)] md:w-[calc(100vw-7%)] lg:h-[calc(100vh-20%)] lg:w-[calc(100vw-30%)]">
|
||||
<DialogPanel className="space-y-4 border border-light-200 dark:border-dark-200 bg-light-primary dark:bg-dark-primary backdrop-blur-lg rounded-xl h-[calc(100vh-2%)] w-[calc(100vw-2%)] md:h-[calc(100vh-7%)] md:w-[calc(100vw-7%)] lg:h-[calc(100vh-20%)] lg:w-[calc(100vw-30%)] overflow-hidden flex flex-col">
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center h-full w-full">
|
||||
<Loader />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-1 inset-0 h-full">
|
||||
<div className="w-[240px] border-r border-white-200 dark:border-dark-200 h-full px-3 pt-3 flex flex-col">
|
||||
<div className="flex flex-1 inset-0 h-full overflow-hidden">
|
||||
<div className="hidden lg:flex flex-col w-[240px] border-r border-white-200 dark:border-dark-200 h-full px-3 pt-3 overflow-y-auto">
|
||||
<button
|
||||
onClick={() => setIsOpen(false)}
|
||||
className="group flex flex-row items-center hover:bg-light-200 hover:dark:bg-dark-200 p-2 rounded-lg"
|
||||
@@ -109,11 +124,11 @@ const SettingsDialogue = ({
|
||||
key={section.dataAdd}
|
||||
className={cn(
|
||||
`flex flex-row items-center space-x-2 px-2 py-1.5 rounded-lg w-full text-sm hover:bg-light-200 hover:dark:bg-dark-200 transition duration-200 active:scale-95`,
|
||||
activeSection.name === section.name
|
||||
activeSection === section.key
|
||||
? 'bg-light-200 dark:bg-dark-200 text-black/90 dark:text-white/90'
|
||||
: ' text-black/70 dark:text-white/70',
|
||||
)}
|
||||
onClick={() => setActiveSection(section)}
|
||||
onClick={() => setActiveSection(section.key)}
|
||||
>
|
||||
<section.icon size={17} />
|
||||
<p>{section.name}</p>
|
||||
@@ -121,23 +136,50 @@ const SettingsDialogue = ({
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
{activeSection.component && (
|
||||
<div className="flex h-full flex-col">
|
||||
<div className="border-b border-light-200/60 px-6 pb-6 pt-8 dark:border-dark-200/60">
|
||||
<div className="w-full flex flex-col overflow-hidden">
|
||||
<div className="flex flex-row lg:hidden w-full justify-between px-[20px] my-4 flex-shrink-0">
|
||||
<button
|
||||
onClick={() => setIsOpen(false)}
|
||||
className="group flex flex-row items-center hover:bg-light-200 hover:dark:bg-dark-200 rounded-lg mr-[40%]"
|
||||
>
|
||||
<ArrowLeft
|
||||
size={18}
|
||||
className="text-black/50 dark:text-white/50 group-hover:text-black/70 group-hover:dark:text-white/70"
|
||||
/>
|
||||
</button>
|
||||
<Select
|
||||
options={sections.map((section) => {
|
||||
return {
|
||||
value: section.key,
|
||||
key: section.key,
|
||||
label: section.name,
|
||||
};
|
||||
})}
|
||||
value={activeSection}
|
||||
onChange={(e) => {
|
||||
setActiveSection(e.target.value);
|
||||
}}
|
||||
className="!text-xs lg:!text-sm"
|
||||
/>
|
||||
</div>
|
||||
{selectedSection.component && (
|
||||
<div className="flex flex-1 flex-col overflow-hidden">
|
||||
<div className="border-b border-light-200/60 px-6 pb-6 lg:pt-6 dark:border-dark-200/60 flex-shrink-0">
|
||||
<div className="flex flex-col">
|
||||
<h4 className="font-medium text-black dark:text-white">
|
||||
{activeSection.name}
|
||||
<h4 className="font-medium text-black dark:text-white text-sm lg:text-base">
|
||||
{selectedSection.name}
|
||||
</h4>
|
||||
<p className="text-xs text-black/50 dark:text-white/50">
|
||||
{activeSection.description}
|
||||
<p className="text-[11px] lg:text-xs text-black/50 dark:text-white/50">
|
||||
{selectedSection.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<activeSection.component
|
||||
fields={config.fields[activeSection.dataAdd]}
|
||||
values={config.values[activeSection.dataAdd]}
|
||||
/>
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<selectedSection.component
|
||||
fields={config.fields[selectedSection.dataAdd]}
|
||||
values={config.values[selectedSection.dataAdd]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@@ -59,11 +59,13 @@ const SettingsSelect = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="rounded-xl border border-light-200 bg-light-primary/80 p-6 transition-colors dark:border-dark-200 dark:bg-dark-primary/80">
|
||||
<div className="space-y-5">
|
||||
<section className="rounded-xl border border-light-200 bg-light-primary/80 p-4 lg:p-6 transition-colors dark:border-dark-200 dark:bg-dark-primary/80">
|
||||
<div className="space-y-3 lg:space-y-5">
|
||||
<div>
|
||||
<h4 className="text-base text-black dark:text-white">{field.name}</h4>
|
||||
<p className="text-xs text-black/50 dark:text-white/50">
|
||||
<h4 className="text-sm lg:text-base text-black dark:text-white">
|
||||
{field.name}
|
||||
</h4>
|
||||
<p className="text-[11px] lg:text-xs text-black/50 dark:text-white/50">
|
||||
{field.description}
|
||||
</p>
|
||||
</div>
|
||||
@@ -74,7 +76,7 @@ const SettingsSelect = ({
|
||||
value: option.value,
|
||||
label: option.name,
|
||||
}))}
|
||||
className="w-full rounded-lg border border-light-200 dark:border-dark-200 bg-light-primary dark:bg-dark-primary px-4 py-3 text-sm text-black/80 dark:text-white/80 placeholder:text-black/40 dark:placeholder:text-white/40 focus-visible:outline-none focus-visible:border-light-300 dark:focus-visible:border-dark-300 transition-colors disabled:cursor-not-allowed disabled:opacity-60 cursor-pointer capitalize pr-12"
|
||||
className="!text-xs lg:!text-sm"
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
/>
|
||||
@@ -128,11 +130,13 @@ const SettingsInput = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="rounded-xl border border-light-200 bg-light-primary/80 p-6 transition-colors dark:border-dark-200 dark:bg-dark-primary/80">
|
||||
<div className="space-y-5">
|
||||
<section className="rounded-xl border border-light-200 bg-light-primary/80 p-4 lg:p-6 transition-colors dark:border-dark-200 dark:bg-dark-primary/80">
|
||||
<div className="space-y-3 lg:space-y-5">
|
||||
<div>
|
||||
<h4 className="text-base text-black dark:text-white">{field.name}</h4>
|
||||
<p className="text-xs text-black/50 dark:text-white/50">
|
||||
<h4 className="text-sm lg:text-base text-black dark:text-white">
|
||||
{field.name}
|
||||
</h4>
|
||||
<p className="text-[11px] lg:text-xs text-black/50 dark:text-white/50">
|
||||
{field.description}
|
||||
</p>
|
||||
</div>
|
||||
@@ -141,7 +145,7 @@ const SettingsInput = ({
|
||||
value={value ?? field.default ?? ''}
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
onBlur={(event) => handleSave(event.target.value)}
|
||||
className="w-full rounded-lg border border-light-200 dark:border-dark-200 bg-light-primary dark:bg-dark-primary px-4 py-3 pr-10 text-sm text-black/80 dark:text-white/80 placeholder:text-black/40 dark:placeholder:text-white/40 focus-visible:outline-none focus-visible:border-light-300 dark:focus-visible:border-dark-300 transition-colors disabled:cursor-not-allowed disabled:opacity-60"
|
||||
className="w-full rounded-lg border border-light-200 dark:border-dark-200 bg-light-primary dark:bg-dark-primary px-3 py-2 lg:px-4 lg:py-3 pr-10 !text-xs lg:!text-sm text-black/80 dark:text-white/80 placeholder:text-black/40 dark:placeholder:text-white/40 focus-visible:outline-none focus-visible:border-light-300 dark:focus-visible:border-dark-300 transition-colors disabled:cursor-not-allowed disabled:opacity-60"
|
||||
placeholder={field.placeholder}
|
||||
type="text"
|
||||
disabled={loading}
|
||||
|
@@ -3,7 +3,7 @@ import { Loader2, ChevronDown } from 'lucide-react';
|
||||
import { SelectHTMLAttributes, forwardRef } from 'react';
|
||||
|
||||
interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
|
||||
options: { value: string; label: string; disabled?: boolean }[];
|
||||
options: { value: any; label: string; disabled?: boolean }[];
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
|
||||
ref={ref}
|
||||
disabled={disabled || loading}
|
||||
className={cn(
|
||||
'bg-light-secondary dark:bg-dark-secondary px-3 py-2 flex items-center overflow-hidden border border-light-200 dark:border-dark-200 dark:text-white rounded-lg text-sm appearance-none w-full pr-10',
|
||||
'bg-light-secondary dark:bg-dark-secondary px-3 py-2 flex items-center overflow-hidden border border-light-200 dark:border-dark-200 dark:text-white rounded-lg appearance-none w-full pr-10 text-xs lg:text-sm',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
Reference in New Issue
Block a user