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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$footer-padding: 1.5rem 1.5rem;
 | 
			
		||||
$fullhd: 2000px;
 | 
			
		||||
$modal-content-width: 1000px;
 | 
			
		||||
// $footer-padding: 1.5rem 1.5rem;
 | 
			
		||||
// $fullhd: 2000px;
 | 
			
		||||
// $modal-content-width: 1000px;
 | 
			
		||||
 | 
			
		||||
@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);
 | 
			
		||||
  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) {
 | 
			
		||||
  .main-menu .dropdown-menu .dropdown-content {
 | 
			
		||||
| 
						 | 
				
			
			@ -594,3 +600,18 @@ aside.menu.main-menu .menu-expanse {
 | 
			
		|||
  border-top-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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -24,13 +24,13 @@
 | 
			
		|||
  }
 | 
			
		||||
  
 | 
			
		||||
  const settingChecks:Record<string, SettingPrompt[]> = {
 | 
			
		||||
    'profile': [
 | 
			
		||||
    profile: [
 | 
			
		||||
      {
 | 
			
		||||
        prompt: 'Unsaved changes to the current profile will be lost.\n Continue?',
 | 
			
		||||
        fn: (setting, newVal, oldVal) => {
 | 
			
		||||
          return !!chatSettings.isDirty && newVal !== oldVal
 | 
			
		||||
        },
 | 
			
		||||
        passed: false,
 | 
			
		||||
        passed: false
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        prompt: 'Personality change will not correctly apply to existing chat session.\n Continue?',
 | 
			
		||||
| 
						 | 
				
			
			@ -38,8 +38,8 @@
 | 
			
		|||
          return chat.sessionStarted && newVal !== originalProfile &&
 | 
			
		||||
            (getProfile(newVal).characterName !== chatSettings.characterName)
 | 
			
		||||
        },
 | 
			
		||||
        passed: false,
 | 
			
		||||
      },
 | 
			
		||||
        passed: false
 | 
			
		||||
      }
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +77,6 @@
 | 
			
		|||
          console.log('Refreshed from setting', setting.key, chatSettings[setting.key], val)
 | 
			
		||||
          refreshSettings()
 | 
			
		||||
        }
 | 
			
		||||
          
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        setChatSettingValue(chatId, setting, val)
 | 
			
		||||
        window.alert('Unable to change:\n' + e.message)
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +86,7 @@
 | 
			
		|||
    const checks = settingChecks[setting.key] || []
 | 
			
		||||
    const newVal = cleanSettingValue(setting.type, el.checked || el.value)
 | 
			
		||||
    for (let i = 0, l = checks.length; i < l; i++) {
 | 
			
		||||
      let c = checks[i]
 | 
			
		||||
      const c = checks[i]
 | 
			
		||||
      if (c.passed) continue
 | 
			
		||||
      if (c.fn(setting, newVal, val)) {
 | 
			
		||||
        // eventually this needs to be an async call to a confirmation modal where
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@
 | 
			
		|||
  import {
 | 
			
		||||
    faTrash,
 | 
			
		||||
    faClone,
 | 
			
		||||
    faEllipsisVertical,
 | 
			
		||||
    faEllipsis,
 | 
			
		||||
    faFloppyDisk,
 | 
			
		||||
    faThumbtack,
 | 
			
		||||
    faDownload,
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +27,7 @@
 | 
			
		|||
  import { exportProfileAsJSON } from './Export.svelte'
 | 
			
		||||
  import { afterUpdate } from 'svelte'
 | 
			
		||||
  import ChatSettingField from './ChatSettingField.svelte'
 | 
			
		||||
    import { getModelMaxTokens } from './Stats.svelte';
 | 
			
		||||
  import { getModelMaxTokens } from './Stats.svelte'
 | 
			
		||||
 | 
			
		||||
  export let chatId:number
 | 
			
		||||
  export const show = () => { showSettings() }
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +50,7 @@
 | 
			
		|||
  $: chatSettings = chat.settings
 | 
			
		||||
  $: globalStore = $globalStorage
 | 
			
		||||
 | 
			
		||||
  let originalProfile = chatSettings && chatSettings.profile
 | 
			
		||||
  const originalProfile = chatSettings && chatSettings.profile
 | 
			
		||||
 | 
			
		||||
  afterUpdate(() => {
 | 
			
		||||
    sizeTextElements()
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +64,7 @@
 | 
			
		|||
 | 
			
		||||
  const clearSettings = () => {
 | 
			
		||||
    resetChatSettings(chatId)
 | 
			
		||||
    showSettingsModal++ // Make sure the dialog updates
 | 
			
		||||
    refreshSettings()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const refreshSettings = async () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -204,10 +204,12 @@
 | 
			
		|||
  // excludeFromProfile
 | 
			
		||||
 | 
			
		||||
  const deepEqual = (x:any, y:any) => {
 | 
			
		||||
    const ok = Object.keys, tx = typeof x, ty = typeof y
 | 
			
		||||
    return x && y && tx === 'object' && tx === ty ? (
 | 
			
		||||
    const ok = Object.keys; const tx = typeof x; const ty = typeof y
 | 
			
		||||
    return x && y && tx === 'object' && tx === ty
 | 
			
		||||
      ? (
 | 
			
		||||
          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) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -228,10 +230,28 @@
 | 
			
		|||
  <div class="modal-card" on:click={() => { showProfileMenu = false }}>
 | 
			
		||||
    <header class="modal-card-head">
 | 
			
		||||
      <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">
 | 
			
		||||
              <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>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="dropdown-menu" id="dropdown-menu3" role="menu">
 | 
			
		||||
| 
						 | 
				
			
			@ -263,19 +283,8 @@
 | 
			
		|||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
    </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">
 | 
			
		||||
      <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>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>  
 | 
			
		||||
    </footer>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,8 +100,6 @@ export const restartProfile = (chatId:number, noApply:boolean=false) => {
 | 
			
		|||
 | 
			
		||||
// Apply currently selected profile
 | 
			
		||||
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
 | 
			
		||||
  if (!resetChat) return
 | 
			
		||||
  return restartProfile(chatId, true)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
<script context="module" lang="ts">
 | 
			
		||||
    import { applyProfile } from './Profiles.svelte'
 | 
			
		||||
    import { getChat, getChatSettings } from './Storage.svelte'
 | 
			
		||||
    import { getChatSettings } from './Storage.svelte'
 | 
			
		||||
    import { encode } from 'gpt-tokenizer'
 | 
			
		||||
// Setting definitions
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +62,7 @@ const gptDefaults = {
 | 
			
		|||
  presence_penalty: 0,
 | 
			
		||||
  frequency_penalty: 0,
 | 
			
		||||
  logit_bias: null,
 | 
			
		||||
  user: undefined,
 | 
			
		||||
  user: undefined
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Core set of defaults
 | 
			
		||||
| 
						 | 
				
			
			@ -82,13 +82,13 @@ const defaults:ChatSettings = {
 | 
			
		|||
  systemPrompt: '',
 | 
			
		||||
  autoStartSession: false,
 | 
			
		||||
  trainingPrompts: [],
 | 
			
		||||
  isDirty: false,
 | 
			
		||||
  isDirty: false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const excludeFromProfile = {
 | 
			
		||||
  messages: true,
 | 
			
		||||
  user: true,
 | 
			
		||||
  isDirty: true,
 | 
			
		||||
  isDirty: true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const profileSetting: ChatSetting & SettingSelect = {
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +103,7 @@ const profileSetting: ChatSetting & SettingSelect = {
 | 
			
		|||
        applyProfile(chatId)
 | 
			
		||||
        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
 | 
			
		||||
| 
						 | 
				
			
			@ -229,7 +229,7 @@ const modelSetting: ChatSetting & SettingSelect = {
 | 
			
		|||
      options: [],
 | 
			
		||||
      type: 'select',
 | 
			
		||||
      forceApi: true, // Need to make sure we send this
 | 
			
		||||
      afterChange: (chatId, setting) => true, // refresh settings
 | 
			
		||||
      afterChange: (chatId, setting) => true // refresh settings
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const chatSettingsList: ChatSetting[] = [
 | 
			
		||||
| 
						 | 
				
			
			@ -276,7 +276,7 @@ const chatSettingsList: ChatSetting[] = [
 | 
			
		|||
        max: 32768,
 | 
			
		||||
        step: 1,
 | 
			
		||||
        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',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue