Clean up UI for settings modal, better for mobile.
This commit is contained in:
parent
43f52e1fd1
commit
a38ce6d702
27
src/app.scss
27
src/app.scss
|
@ -157,9 +157,9 @@ html {
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
$footer-padding: 1.5rem 1.5rem;
|
// $footer-padding: 1.5rem 1.5rem;
|
||||||
$fullhd: 2000px;
|
// $fullhd: 2000px;
|
||||||
$modal-content-width: 1000px;
|
// $modal-content-width: 1000px;
|
||||||
|
|
||||||
@import "/node_modules/bulma/bulma.sass";
|
@import "/node_modules/bulma/bulma.sass";
|
||||||
|
|
||||||
|
@ -277,6 +277,12 @@ $modal-background-background-color-dark: rgba($dark, 0.86) !default; // remove t
|
||||||
max-height: calc(100vh - 60px);
|
max-height: calc(100vh - 60px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
.modal-card .dropdown-menu .dropdown-content {
|
||||||
|
max-height: calc(100vh - 80px);
|
||||||
|
}
|
||||||
|
.modal-card {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 768px) {
|
@media only screen and (max-width: 768px) {
|
||||||
.main-menu .dropdown-menu .dropdown-content {
|
.main-menu .dropdown-menu .dropdown-content {
|
||||||
|
@ -594,3 +600,18 @@ aside.menu.main-menu .menu-expanse {
|
||||||
border-top-left-radius: 0px !important;
|
border-top-left-radius: 0px !important;
|
||||||
border-bottom-left-radius: 0px !important;
|
border-bottom-left-radius: 0px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-card footer {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.modal-card footer .level {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-card header, .modal-card footer, .modal-card .notification {
|
||||||
|
padding: .8em;
|
||||||
|
}
|
||||||
|
.modal-card .notification {
|
||||||
|
margin-left: -.5em;
|
||||||
|
margin-right: -.5em;
|
||||||
|
}
|
|
@ -92,7 +92,7 @@
|
||||||
<span class="menu-icon"><Fa icon={faGear}/></span> Chat Profile Settings
|
<span class="menu-icon"><Fa icon={faGear}/></span> Chat Profile Settings
|
||||||
</a>
|
</a>
|
||||||
<hr class="dropdown-divider">
|
<hr class="dropdown-divider">
|
||||||
<a href={$apiKeyStorage?'#/chat/new':'#/'} class:is-disabled={!$apiKeyStorage} on:click={() => close()} class="dropdown-item">
|
<a href={$apiKeyStorage ? '#/chat/new' : '#/'} class:is-disabled={!$apiKeyStorage} on:click={() => close()} class="dropdown-item">
|
||||||
<span class="menu-icon"><Fa icon={faSquarePlus}/></span> New Chat
|
<span class="menu-icon"><Fa icon={faSquarePlus}/></span> New Chat
|
||||||
</a>
|
</a>
|
||||||
<a href={'#'} class="dropdown-item" class:is-disabled={!chatId} on:click|preventDefault={() => { if (chatId) close(); copyChat(chatId) }}>
|
<a href={'#'} class="dropdown-item" class:is-disabled={!chatId} on:click|preventDefault={() => { if (chatId) close(); copyChat(chatId) }}>
|
||||||
|
|
|
@ -24,28 +24,28 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingChecks:Record<string, SettingPrompt[]> = {
|
const settingChecks:Record<string, SettingPrompt[]> = {
|
||||||
'profile': [
|
profile: [
|
||||||
{
|
{
|
||||||
prompt:'Unsaved changes to the current profile will be lost.\n Continue?',
|
prompt: 'Unsaved changes to the current profile will be lost.\n Continue?',
|
||||||
fn: (setting, newVal, oldVal) => {
|
fn: (setting, newVal, oldVal) => {
|
||||||
return !!chatSettings.isDirty && newVal !== oldVal
|
return !!chatSettings.isDirty && newVal !== oldVal
|
||||||
},
|
},
|
||||||
passed: false,
|
passed: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prompt:'Personality change will not correctly apply to existing chat session.\n Continue?',
|
prompt: 'Personality change will not correctly apply to existing chat session.\n Continue?',
|
||||||
fn: (setting, newVal, oldVal) => {
|
fn: (setting, newVal, oldVal) => {
|
||||||
return chat.sessionStarted && newVal !== originalProfile &&
|
return chat.sessionStarted && newVal !== originalProfile &&
|
||||||
(getProfile(newVal).characterName !== chatSettings.characterName)
|
(getProfile(newVal).characterName !== chatSettings.characterName)
|
||||||
},
|
},
|
||||||
passed: false,
|
passed: false
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetSettingCheck = (key:keyof ChatSettings) => {
|
const resetSettingCheck = (key:keyof ChatSettings) => {
|
||||||
const checks = settingChecks[key]
|
const checks = settingChecks[key]
|
||||||
checks && checks.forEach((c)=>{c.passed=false})
|
checks && checks.forEach((c) => { c.passed = false })
|
||||||
}
|
}
|
||||||
|
|
||||||
let debounce: any
|
let debounce: any
|
||||||
|
@ -73,11 +73,10 @@
|
||||||
const newVal = chatSettings[setting.key]
|
const newVal = chatSettings[setting.key]
|
||||||
if (val === newVal) return
|
if (val === newVal) return
|
||||||
try {
|
try {
|
||||||
if((typeof setting.afterChange === 'function') && setting.afterChange(chatId, setting, chatSettings[setting.key])){
|
if ((typeof setting.afterChange === 'function') && setting.afterChange(chatId, setting, chatSettings[setting.key])) {
|
||||||
console.log('Refreshed from setting', setting.key, chatSettings[setting.key], val)
|
console.log('Refreshed from setting', setting.key, chatSettings[setting.key], val)
|
||||||
refreshSettings()
|
refreshSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setChatSettingValue(chatId, setting, val)
|
setChatSettingValue(chatId, setting, val)
|
||||||
window.alert('Unable to change:\n' + e.message)
|
window.alert('Unable to change:\n' + e.message)
|
||||||
|
@ -85,10 +84,10 @@
|
||||||
dispatch('change', setting)
|
dispatch('change', setting)
|
||||||
}
|
}
|
||||||
const checks = settingChecks[setting.key] || []
|
const checks = settingChecks[setting.key] || []
|
||||||
const newVal = cleanSettingValue(setting.type, el.checked||el.value)
|
const newVal = cleanSettingValue(setting.type, el.checked || el.value)
|
||||||
for (let i = 0, l = checks.length; i < l; i++) {
|
for (let i = 0, l = checks.length; i < l; i++) {
|
||||||
let c = checks[i]
|
const c = checks[i]
|
||||||
if(c.passed) continue
|
if (c.passed) continue
|
||||||
if (c.fn(setting, newVal, val)) {
|
if (c.fn(setting, newVal, val)) {
|
||||||
// eventually this needs to be an async call to a confirmation modal where
|
// eventually this needs to be an async call to a confirmation modal where
|
||||||
// "passed", not really being used here, will be reworked to some other
|
// "passed", not really being used here, will be reworked to some other
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
import {
|
import {
|
||||||
faTrash,
|
faTrash,
|
||||||
faClone,
|
faClone,
|
||||||
faEllipsisVertical,
|
faEllipsis,
|
||||||
faFloppyDisk,
|
faFloppyDisk,
|
||||||
faThumbtack,
|
faThumbtack,
|
||||||
faDownload,
|
faDownload,
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
import { exportProfileAsJSON } from './Export.svelte'
|
import { exportProfileAsJSON } from './Export.svelte'
|
||||||
import { afterUpdate } from 'svelte'
|
import { afterUpdate } from 'svelte'
|
||||||
import ChatSettingField from './ChatSettingField.svelte'
|
import ChatSettingField from './ChatSettingField.svelte'
|
||||||
import { getModelMaxTokens } from './Stats.svelte';
|
import { getModelMaxTokens } from './Stats.svelte'
|
||||||
|
|
||||||
export let chatId:number
|
export let chatId:number
|
||||||
export const show = () => { showSettings() }
|
export const show = () => { showSettings() }
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
$: chatSettings = chat.settings
|
$: chatSettings = chat.settings
|
||||||
$: globalStore = $globalStorage
|
$: globalStore = $globalStorage
|
||||||
|
|
||||||
let originalProfile = chatSettings && chatSettings.profile
|
const originalProfile = chatSettings && chatSettings.profile
|
||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
sizeTextElements()
|
sizeTextElements()
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
|
|
||||||
const clearSettings = () => {
|
const clearSettings = () => {
|
||||||
resetChatSettings(chatId)
|
resetChatSettings(chatId)
|
||||||
showSettingsModal++ // Make sure the dialog updates
|
refreshSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshSettings = async () => {
|
const refreshSettings = async () => {
|
||||||
|
@ -131,7 +131,7 @@
|
||||||
const profileSelect = getChatSettingObjectByKey('profile') as ChatSetting & SettingSelect
|
const profileSelect = getChatSettingObjectByKey('profile') as ChatSetting & SettingSelect
|
||||||
profileSelect.options = getProfileSelect()
|
profileSelect.options = getProfileSelect()
|
||||||
chatDefaults.profile = getDefaultProfileKey()
|
chatDefaults.profile = getDefaultProfileKey()
|
||||||
chatDefaults.max_tokens = getModelMaxTokens(chatSettings.model||'')
|
chatDefaults.max_tokens = getModelMaxTokens(chatSettings.model || '')
|
||||||
// const defaultProfile = globalStore.defaultProfile || profileSelect.options[0].value
|
// const defaultProfile = globalStore.defaultProfile || profileSelect.options[0].value
|
||||||
defaultProfile = getDefaultProfileKey()
|
defaultProfile = getDefaultProfileKey()
|
||||||
isDefault = defaultProfile === chatSettings.profile
|
isDefault = defaultProfile === chatSettings.profile
|
||||||
|
@ -204,10 +204,12 @@
|
||||||
// excludeFromProfile
|
// excludeFromProfile
|
||||||
|
|
||||||
const deepEqual = (x:any, y:any) => {
|
const deepEqual = (x:any, y:any) => {
|
||||||
const ok = Object.keys, tx = typeof x, ty = typeof y
|
const ok = Object.keys; const tx = typeof x; const ty = typeof y
|
||||||
return x && y && tx === 'object' && tx === ty ? (
|
return x && y && tx === 'object' && tx === ty
|
||||||
|
? (
|
||||||
ok(x).every(key => excludeFromProfile[key] || deepEqual(x[key], y[key]))
|
ok(x).every(key => excludeFromProfile[key] || deepEqual(x[key], y[key]))
|
||||||
) : (x === y || ((x===undefined||x===null||x===false) && (y===undefined||y===null||y===false)))
|
)
|
||||||
|
: (x === y || ((x === undefined || x === null || x === false) && (y === undefined || y === null || y === false)))
|
||||||
}
|
}
|
||||||
|
|
||||||
const setDirty = (e:CustomEvent|undefined = undefined) => {
|
const setDirty = (e:CustomEvent|undefined = undefined) => {
|
||||||
|
@ -228,10 +230,28 @@
|
||||||
<div class="modal-card" on:click={() => { showProfileMenu = false }}>
|
<div class="modal-card" on:click={() => { showProfileMenu = false }}>
|
||||||
<header class="modal-card-head">
|
<header class="modal-card-head">
|
||||||
<p class="modal-card-title">Chat Settings</p>
|
<p class="modal-card-title">Chat Settings</p>
|
||||||
<div class="dropdown is-right" class:is-active={showProfileMenu}>
|
<button class="delete" aria-label="close" on:click={closeSettings}></button>
|
||||||
|
</header>
|
||||||
|
<section class="modal-card-body">
|
||||||
|
{#key showSettingsModal}
|
||||||
|
{#each settingsList as setting}
|
||||||
|
<ChatSettingField on:refresh={refreshSettings} on:change={setDirty} chat={chat} chatDefaults={chatDefaults} chatSettings={chatSettings} setting={setting} originalProfile={originalProfile} />
|
||||||
|
{/each}
|
||||||
|
{/key}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer class="modal-card-foot">
|
||||||
|
<div class="level is-mobile">
|
||||||
|
<div class="level-left">
|
||||||
|
<!-- <button class="button is-info" on:click={closeSettings}>Close</button> -->
|
||||||
|
<button class="button" class:is-disabled={!chatSettings.isDirty} on:click={saveProfile}>Save Changes</button>
|
||||||
|
<button class="button is-warning" class:is-disabled={!chatSettings.isDirty} on:click={clearSettings}>Reset</button>
|
||||||
|
</div>
|
||||||
|
<div class="level-right">
|
||||||
|
<div class="dropdown is-right is-up" class:is-active={showProfileMenu}>
|
||||||
<div class="dropdown-trigger">
|
<div class="dropdown-trigger">
|
||||||
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu3" on:click|preventDefault|stopPropagation={() => { showProfileMenu = !showProfileMenu }}>
|
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu3" on:click|preventDefault|stopPropagation={() => { showProfileMenu = !showProfileMenu }}>
|
||||||
<span><Fa icon={faEllipsisVertical}/></span>
|
<span class="icon"><Fa icon={faEllipsis}/></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown-menu" id="dropdown-menu3" role="menu">
|
<div class="dropdown-menu" id="dropdown-menu3" role="menu">
|
||||||
|
@ -263,19 +283,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</div>
|
||||||
<section class="modal-card-body">
|
</div>
|
||||||
{#key showSettingsModal}
|
|
||||||
{#each settingsList as setting}
|
|
||||||
<ChatSettingField on:refresh={refreshSettings} on:change={setDirty} chat={chat} chatDefaults={chatDefaults} chatSettings={chatSettings} setting={setting} originalProfile={originalProfile} />
|
|
||||||
{/each}
|
|
||||||
{/key}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<footer class="modal-card-foot">
|
|
||||||
<button class="button is-info" on:click={closeSettings}>Close</button>
|
|
||||||
<button class="button is-warning" on:click={clearSettings}>Reset</button>
|
|
||||||
<button class="button" class:is-disabled={!chatSettings.isDirty} on:click={saveProfile}>Save Changes</button>
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -72,7 +72,7 @@ export const prepareSummaryPrompt = (chatId:number, promptsSize:number, maxToken
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restart currently loaded profile
|
// Restart currently loaded profile
|
||||||
export const restartProfile = (chatId:number, noApply:boolean=false) => {
|
export const restartProfile = (chatId:number, noApply:boolean = false) => {
|
||||||
const settings = getChatSettings(chatId)
|
const settings = getChatSettings(chatId)
|
||||||
if (!settings.profile && !noApply) return applyProfile(chatId, '', true)
|
if (!settings.profile && !noApply) return applyProfile(chatId, '', true)
|
||||||
// Clear current messages
|
// Clear current messages
|
||||||
|
@ -100,8 +100,6 @@ export const restartProfile = (chatId:number, noApply:boolean=false) => {
|
||||||
|
|
||||||
// Apply currently selected profile
|
// Apply currently selected profile
|
||||||
export const applyProfile = (chatId:number, key:string = '', resetChat:boolean = false) => {
|
export const applyProfile = (chatId:number, key:string = '', resetChat:boolean = false) => {
|
||||||
const settings = getChatSettings(chatId)
|
|
||||||
const profile = getProfile(key || settings.profile)
|
|
||||||
resetChatSettings(chatId, resetChat) // Fully reset
|
resetChatSettings(chatId, resetChat) // Fully reset
|
||||||
if (!resetChat) return
|
if (!resetChat) return
|
||||||
return restartProfile(chatId, true)
|
return restartProfile(chatId, true)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script context="module" lang="ts">
|
<script context="module" lang="ts">
|
||||||
import { applyProfile } from './Profiles.svelte'
|
import { applyProfile } from './Profiles.svelte'
|
||||||
import { getChat, getChatSettings } from './Storage.svelte'
|
import { getChatSettings } from './Storage.svelte'
|
||||||
import { encode } from 'gpt-tokenizer'
|
import { encode } from 'gpt-tokenizer'
|
||||||
// Setting definitions
|
// Setting definitions
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ const gptDefaults = {
|
||||||
presence_penalty: 0,
|
presence_penalty: 0,
|
||||||
frequency_penalty: 0,
|
frequency_penalty: 0,
|
||||||
logit_bias: null,
|
logit_bias: null,
|
||||||
user: undefined,
|
user: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
// Core set of defaults
|
// Core set of defaults
|
||||||
|
@ -82,13 +82,13 @@ const defaults:ChatSettings = {
|
||||||
systemPrompt: '',
|
systemPrompt: '',
|
||||||
autoStartSession: false,
|
autoStartSession: false,
|
||||||
trainingPrompts: [],
|
trainingPrompts: [],
|
||||||
isDirty: false,
|
isDirty: false
|
||||||
}
|
}
|
||||||
|
|
||||||
const excludeFromProfile = {
|
const excludeFromProfile = {
|
||||||
messages: true,
|
messages: true,
|
||||||
user: true,
|
user: true,
|
||||||
isDirty: true,
|
isDirty: true
|
||||||
}
|
}
|
||||||
|
|
||||||
const profileSetting: ChatSetting & SettingSelect = {
|
const profileSetting: ChatSetting & SettingSelect = {
|
||||||
|
@ -103,7 +103,7 @@ const profileSetting: ChatSetting & SettingSelect = {
|
||||||
applyProfile(chatId)
|
applyProfile(chatId)
|
||||||
return true // Signal we should refresh the setting modal
|
return true // Signal we should refresh the setting modal
|
||||||
},
|
},
|
||||||
setDefault: (chatId, setting, value) => {},
|
setDefault: (chatId, setting, value) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings that will not be part of the API request
|
// Settings that will not be part of the API request
|
||||||
|
@ -229,7 +229,7 @@ const modelSetting: ChatSetting & SettingSelect = {
|
||||||
options: [],
|
options: [],
|
||||||
type: 'select',
|
type: 'select',
|
||||||
forceApi: true, // Need to make sure we send this
|
forceApi: true, // Need to make sure we send this
|
||||||
afterChange: (chatId, setting) => true, // refresh settings
|
afterChange: (chatId, setting) => true // refresh settings
|
||||||
}
|
}
|
||||||
|
|
||||||
const chatSettingsList: ChatSetting[] = [
|
const chatSettingsList: ChatSetting[] = [
|
||||||
|
@ -276,7 +276,7 @@ const chatSettingsList: ChatSetting[] = [
|
||||||
max: 32768,
|
max: 32768,
|
||||||
step: 1,
|
step: 1,
|
||||||
type: 'number',
|
type: 'number',
|
||||||
forceApi: true, // Since default here is different than gpt default, will make sure we always send it
|
forceApi: true // Since default here is different than gpt default, will make sure we always send it
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'presence_penalty',
|
key: 'presence_penalty',
|
||||||
|
|
Loading…
Reference in New Issue