minor improvements

This commit is contained in:
Egor 2025-09-03 20:40:38 -07:00
parent d7e09f2ea5
commit 8c7edeae1a
14 changed files with 107 additions and 78 deletions

View file

@ -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>

View file

@ -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">

View file

@ -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">

View file

@ -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',
}}

View file

@ -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">

View file

@ -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)'

View file

@ -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>

View file

@ -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

View file

@ -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,

View file

@ -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',

View file

@ -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(

View file

@ -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'],

View file

@ -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);
},
}));

View file

@ -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(' ');
};