mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 09:33:10 -07:00
minor improvements
This commit is contained in:
parent
b0c6087e41
commit
1ff27a893b
14 changed files with 107 additions and 78 deletions
17
src/App.tsx
17
src/App.tsx
|
|
@ -12,7 +12,6 @@ import { TitleBar } from '@/components/TitleBar';
|
|||
import { ErrorBoundary } from '@/components/ErrorBoundary';
|
||||
import { useUpdateChecker } from '@/hooks/useUpdateChecker';
|
||||
import { useKoboldVersions } from '@/hooks/useKoboldVersions';
|
||||
import { useModalStore } from '@/stores/modal';
|
||||
import { safeExecute } from '@/utils/logger';
|
||||
import { TITLEBAR_HEIGHT } from '@/constants';
|
||||
import type { DownloadItem } from '@/types/electron';
|
||||
|
|
@ -25,8 +24,8 @@ export const App = () => {
|
|||
useState<InterfaceTab>('terminal');
|
||||
const [frontendPreference, setFrontendPreference] =
|
||||
useState<FrontendPreference>('koboldcpp');
|
||||
|
||||
const { modals, setModalOpen } = useModalStore();
|
||||
const [settingsModalOpen, setSettingsModalOpen] = useState(false);
|
||||
const [ejectConfirmModalOpen, setEjectConfirmModalOpen] = useState(false);
|
||||
|
||||
const {
|
||||
updateInfo: binaryUpdateInfo,
|
||||
|
|
@ -121,7 +120,7 @@ export const App = () => {
|
|||
if (skipEjectConfirmation) {
|
||||
performEject();
|
||||
} else {
|
||||
setModalOpen('ejectConfirm', true);
|
||||
setEjectConfirmModalOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -158,7 +157,7 @@ export const App = () => {
|
|||
currentTab={activeInterfaceTab}
|
||||
onTabChange={setActiveInterfaceTab}
|
||||
onEject={handleEject}
|
||||
onOpenSettings={() => setModalOpen('settings', true)}
|
||||
onOpenSettings={() => setSettingsModalOpen(true)}
|
||||
frontendPreference={frontendPreference}
|
||||
/>
|
||||
|
||||
|
|
@ -225,9 +224,9 @@ export const App = () => {
|
|||
/>
|
||||
</AppShell.Main>
|
||||
<SettingsModal
|
||||
opened={modals.settings}
|
||||
opened={settingsModalOpen}
|
||||
onClose={async () => {
|
||||
setModalOpen('settings', false);
|
||||
setSettingsModalOpen(false);
|
||||
const preference = await safeExecute(
|
||||
() =>
|
||||
window.electronAPI.config.get(
|
||||
|
|
@ -240,8 +239,8 @@ export const App = () => {
|
|||
currentScreen={currentScreen || undefined}
|
||||
/>
|
||||
<EjectConfirmModal
|
||||
opened={modals.ejectConfirm}
|
||||
onClose={() => setModalOpen('ejectConfirm', false)}
|
||||
opened={ejectConfirmModalOpen}
|
||||
onClose={() => setEjectConfirmModalOpen(false)}
|
||||
onConfirm={handleEjectConfirm}
|
||||
/>
|
||||
</AppShell>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { MODAL_STYLES_WITH_TITLEBAR } from '@/constants';
|
||||
import {
|
||||
Modal,
|
||||
Text,
|
||||
|
|
@ -549,7 +550,7 @@ export const CommandLineArgumentsModal = ({
|
|||
>
|
||||
<Group gap="xs" wrap="wrap" justify="space-between">
|
||||
<Group gap="xs" wrap="wrap" style={{ flex: 1 }}>
|
||||
<Code style={{ fontSize: '0.875rem', fontWeight: 600 }}>
|
||||
<Code style={{ fontSize: '0.875em', fontWeight: 600 }}>
|
||||
{arg.flag}
|
||||
</Code>
|
||||
{arg.aliases &&
|
||||
|
|
@ -609,6 +610,7 @@ export const CommandLineArgumentsModal = ({
|
|||
title="Available Command Line Arguments"
|
||||
size="xl"
|
||||
centered
|
||||
styles={MODAL_STYLES_WITH_TITLEBAR}
|
||||
>
|
||||
<Stack gap="md">
|
||||
<Text size="sm" c="dimmed">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { useState } from 'react';
|
||||
import { Modal, Text, Group, Button, Checkbox, Stack } from '@mantine/core';
|
||||
import { MODAL_STYLES_WITH_TITLEBAR } from '@/constants';
|
||||
|
||||
interface EjectConfirmModalProps {
|
||||
opened: boolean;
|
||||
|
|
@ -32,6 +33,7 @@ export const EjectConfirmModal = ({
|
|||
centered
|
||||
closeOnClickOutside={false}
|
||||
closeOnEscape={false}
|
||||
styles={MODAL_STYLES_WITH_TITLEBAR}
|
||||
>
|
||||
<Stack gap="md">
|
||||
<Text size="sm" c="dimmed">
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import {
|
|||
import { useState } from 'react';
|
||||
import { soundAssets, playSound, initializeAudio } from '@/utils/sounds';
|
||||
import { useAppUpdateChecker } from '@/hooks/useAppUpdateChecker';
|
||||
import { useModalStore } from '@/stores/modal';
|
||||
import { useLaunchConfigStore } from '@/stores/launchConfig';
|
||||
import iconUrl from '/icon.png';
|
||||
import { FRONTENDS, PRODUCT_NAME, TITLEBAR_HEIGHT } from '@/constants';
|
||||
|
|
@ -45,7 +44,6 @@ export const TitleBar = ({
|
|||
getInitialValueInEffect: false,
|
||||
});
|
||||
const { hasUpdate, openReleasePage } = useAppUpdateChecker();
|
||||
const { isAnyModalOpen } = useModalStore();
|
||||
const { isImageGenerationMode } = useLaunchConfigStore();
|
||||
const [logoClickCount, setLogoClickCount] = useState(0);
|
||||
const [isElephantMode, setIsElephantMode] = useState(false);
|
||||
|
|
@ -106,8 +104,7 @@ export const TitleBar = ({
|
|||
? 'var(--mantine-color-dark-8)'
|
||||
: 'var(--mantine-color-gray-1)',
|
||||
borderBottom: '1px solid var(--mantine-color-default-border)',
|
||||
WebkitAppRegion:
|
||||
isAnyModalOpen() || isSelectOpen ? 'no-drag' : 'drag',
|
||||
WebkitAppRegion: isSelectOpen ? 'no-drag' : 'drag',
|
||||
userSelect: 'none',
|
||||
position: 'relative',
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { Download, X, ExternalLink } from 'lucide-react';
|
|||
import { useState } from 'react';
|
||||
import type { InstalledVersion, DownloadItem } from '@/types/electron';
|
||||
import { getDisplayNameFromPath } from '@/utils/version';
|
||||
import { GITHUB_API } from '@/constants';
|
||||
import { GITHUB_API, MODAL_STYLES_WITH_TITLEBAR } from '@/constants';
|
||||
import { safeExecute } from '@/utils/logger';
|
||||
|
||||
interface UpdateAvailableModalProps {
|
||||
|
|
@ -57,6 +57,7 @@ export const UpdateAvailableModal = ({
|
|||
centered
|
||||
closeOnClickOutside={false}
|
||||
closeOnEscape={!isDownloading && !isUpdating}
|
||||
styles={MODAL_STYLES_WITH_TITLEBAR}
|
||||
>
|
||||
<Stack gap="md">
|
||||
<Card withBorder radius="md" p="md" bd="2px solid orange">
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ export const TerminalTab = ({
|
|||
margin: 0,
|
||||
fontFamily:
|
||||
'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
|
||||
fontSize: '0.875rem',
|
||||
fontSize: '0.875em',
|
||||
lineHeight: 1.4,
|
||||
color: isDark
|
||||
? 'var(--mantine-color-gray-0)'
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import { InfoTooltip } from '@/components/InfoTooltip';
|
|||
import { CheckboxWithTooltip } from '@/components/CheckboxWithTooltip';
|
||||
import { CommandLineArgumentsModal } from '@/components/CommandLineArgumentsModal';
|
||||
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
|
||||
import { useModalStore } from '@/stores/modal';
|
||||
import { safeExecute } from '@/utils/logger';
|
||||
|
||||
export const AdvancedTab = () => {
|
||||
|
|
@ -38,7 +37,7 @@ export const AdvancedTab = () => {
|
|||
handleMoecpuChange,
|
||||
handleMoeexpertsChange,
|
||||
} = useLaunchConfig();
|
||||
const { modals, setModalOpen } = useModalStore();
|
||||
const [commandLineModalOpen, setCommandLineModalOpen] = useState(false);
|
||||
const [backendSupport, setBackendSupport] = useState<{
|
||||
noavx2: boolean;
|
||||
failsafe: boolean;
|
||||
|
|
@ -222,7 +221,7 @@ export const AdvancedTab = () => {
|
|||
<Button
|
||||
size="xs"
|
||||
variant="light"
|
||||
onClick={() => setModalOpen('commandLineArguments', true)}
|
||||
onClick={() => setCommandLineModalOpen(true)}
|
||||
>
|
||||
View Available Arguments
|
||||
</Button>
|
||||
|
|
@ -237,8 +236,8 @@ export const AdvancedTab = () => {
|
|||
</div>
|
||||
|
||||
<CommandLineArgumentsModal
|
||||
opened={modals.commandLineArguments}
|
||||
onClose={() => setModalOpen('commandLineArguments', false)}
|
||||
opened={commandLineModalOpen}
|
||||
onClose={() => setCommandLineModalOpen(false)}
|
||||
onAddArgument={handleAddArgument}
|
||||
/>
|
||||
</Stack>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { MODAL_STYLES_WITH_TITLEBAR } from '@/constants';
|
||||
import { Modal, TextInput, Group, Button, Stack } from '@mantine/core';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
|
|
@ -45,6 +46,7 @@ export const CreateConfigModal = ({
|
|||
onClose={handleClose}
|
||||
title="Create New Configuration"
|
||||
size="sm"
|
||||
styles={MODAL_STYLES_WITH_TITLEBAR}
|
||||
>
|
||||
<Stack gap="md">
|
||||
<TextInput
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { VersionsTab } from '@/components/settings/VersionsTab';
|
|||
import { AppearanceTab } from '@/components/settings/AppearanceTab';
|
||||
import { AboutTab } from '@/components/settings/AboutTab';
|
||||
import type { Screen } from '@/types';
|
||||
import { MODAL_STYLES_WITH_TITLEBAR } from '@/constants';
|
||||
|
||||
interface SettingsModalProps {
|
||||
opened: boolean;
|
||||
|
|
@ -67,17 +68,18 @@ export const SettingsModal = ({
|
|||
centered
|
||||
lockScroll={false}
|
||||
styles={{
|
||||
...MODAL_STYLES_WITH_TITLEBAR,
|
||||
content: {
|
||||
...MODAL_STYLES_WITH_TITLEBAR.content,
|
||||
paddingBottom: 0,
|
||||
},
|
||||
body: {
|
||||
height: '27.5rem',
|
||||
height: '70vh',
|
||||
padding: 0,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
},
|
||||
content: {
|
||||
height: '31.25rem',
|
||||
paddingBottom: 0,
|
||||
},
|
||||
}}
|
||||
transitionProps={{
|
||||
duration: 200,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,15 @@ export const CONFIG_FILE_NAME = 'config.json';
|
|||
|
||||
export const TITLEBAR_HEIGHT = '2.5rem';
|
||||
|
||||
export const MODAL_STYLES_WITH_TITLEBAR = {
|
||||
overlay: {
|
||||
top: TITLEBAR_HEIGHT,
|
||||
},
|
||||
content: {
|
||||
marginTop: TITLEBAR_HEIGHT,
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const SERVER_READY_SIGNALS = {
|
||||
KOBOLDCPP: 'Please connect to custom endpoint at',
|
||||
SILLYTAVERN: 'SillyTavern is listening on',
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ export class IPCHandlers {
|
|||
);
|
||||
|
||||
ipcMain.handle('kobold:getCurrentInstallDir', () =>
|
||||
this.koboldManager.getCurrentInstallDir()
|
||||
this.configManager.getInstallDir()
|
||||
);
|
||||
|
||||
ipcMain.handle('kobold:selectInstallDirectory', () =>
|
||||
|
|
@ -187,6 +187,7 @@ export class IPCHandlers {
|
|||
try {
|
||||
const logsDir = this.logManager.getLogsDirectory();
|
||||
await shell.openPath(logsDir);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
this.logManager.logError('Failed to open logs folder:', error as Error);
|
||||
throw new Error(
|
||||
|
|
|
|||
|
|
@ -531,14 +531,6 @@ export class KoboldCppManager {
|
|||
}
|
||||
}
|
||||
|
||||
getCurrentInstallDir() {
|
||||
return this.configManager.getInstallDir();
|
||||
}
|
||||
|
||||
getWindowManager() {
|
||||
return this.windowManager;
|
||||
}
|
||||
|
||||
async selectInstallDirectory(): Promise<string | null> {
|
||||
const result = await dialog.showOpenDialog({
|
||||
properties: ['openDirectory', 'createDirectory'],
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
import { create } from 'zustand';
|
||||
|
||||
interface ModalState {
|
||||
modals: {
|
||||
settings: boolean;
|
||||
ejectConfirm: boolean;
|
||||
updateAvailable: boolean;
|
||||
commandLineArguments: boolean;
|
||||
};
|
||||
setModalOpen: (
|
||||
modalName: keyof ModalState['modals'],
|
||||
isOpen: boolean
|
||||
) => void;
|
||||
isAnyModalOpen: () => boolean;
|
||||
}
|
||||
|
||||
export const useModalStore = create<ModalState>((set, get) => ({
|
||||
modals: {
|
||||
settings: false,
|
||||
ejectConfirm: false,
|
||||
updateAvailable: false,
|
||||
commandLineArguments: false,
|
||||
},
|
||||
setModalOpen: (modalName, isOpen) =>
|
||||
set((state) => ({
|
||||
modals: {
|
||||
...state.modals,
|
||||
[modalName]: isOpen,
|
||||
},
|
||||
})),
|
||||
isAnyModalOpen: () => {
|
||||
const { modals } = get();
|
||||
return Object.values(modals).some(Boolean);
|
||||
},
|
||||
}));
|
||||
|
|
@ -54,11 +54,69 @@ export const sortDownloadsByType = <T extends { name: string }>(
|
|||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
export const pretifyBinName = (binName: string) =>
|
||||
binName
|
||||
.replace('koboldcpp-', '')
|
||||
.replace('-x64', ' (x64) ')
|
||||
.replace(' -', ' ')
|
||||
.replace('rocm', '- ROCm')
|
||||
.replace('nocuda', '- NoCUDA')
|
||||
.replace('oldpc', '- OldPC');
|
||||
export const pretifyBinName = (binName: string): string => {
|
||||
const cleanName = stripAssetExtensions(binName);
|
||||
|
||||
let name = cleanName.replace(/^koboldcpp[-_]?/, '');
|
||||
|
||||
if (!name) {
|
||||
return 'Windows (x64)';
|
||||
}
|
||||
|
||||
const platforms = {
|
||||
linux: 'Linux',
|
||||
mac: 'macOS',
|
||||
};
|
||||
|
||||
const architectures = {
|
||||
x64: 'x64',
|
||||
arm64: 'ARM64',
|
||||
};
|
||||
|
||||
const variants = {
|
||||
rocm: 'ROCm',
|
||||
nocuda: 'NoCUDA',
|
||||
oldpc: 'OldPC',
|
||||
};
|
||||
|
||||
const parts: string[] = [];
|
||||
let workingName = name.toLowerCase();
|
||||
|
||||
let platform = '';
|
||||
for (const [key, value] of Object.entries(platforms)) {
|
||||
if (workingName.includes(key)) {
|
||||
platform = value;
|
||||
workingName = workingName.replace(key, '').replace(/^-+|-+$/g, '');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let arch = '';
|
||||
for (const [key, value] of Object.entries(architectures)) {
|
||||
if (workingName.includes(key)) {
|
||||
arch = value;
|
||||
workingName = workingName.replace(key, '').replace(/^-+|-+$/g, '');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const foundVariants: string[] = [];
|
||||
for (const [key, value] of Object.entries(variants)) {
|
||||
if (workingName.includes(key)) {
|
||||
foundVariants.push(value);
|
||||
workingName = workingName.replace(key, '').replace(/^-+|-+$/g, '');
|
||||
}
|
||||
}
|
||||
|
||||
if (platform) parts.push(platform);
|
||||
if (arch) parts.push(`(${arch})`);
|
||||
if (foundVariants.length > 0) {
|
||||
parts.push(`- ${foundVariants.join(', ')}`);
|
||||
}
|
||||
|
||||
if (parts.length === 0) {
|
||||
return cleanName.replace('koboldcpp-', '').replace(/^-+/, '') || 'Standard';
|
||||
}
|
||||
|
||||
return parts.join(' ');
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue