fix: one header per application settings page (#148) (#152)

* fix: one header per application settings page (#148)

* fix: registry-owned page header copy, searchable for markup descriptions (#148)

* fix: host descriptionHtml in a div, not an inline span (#148)
This commit is contained in:
veguAI
2026-07-25 17:36:29 +03:00
committed by GitHub
parent 33277bbef6
commit 459bc137eb
15 changed files with 21 additions and 81 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -1,13 +1,5 @@
<template>
<div class="ma-3">
<v-alert color="white" variant="text" icon="mdi-image-outline" density="compact" class="mb-3">
<v-alert-title>Message Visual Rendering</v-alert-title>
<div class="text-grey">
Control when visuals are rendered inline with scene messages.
</div>
</v-alert>
<v-divider class="mb-3"></v-divider>
<v-row class="mb-3">
<v-col cols="12">
<v-checkbox

View File

@@ -50,14 +50,7 @@
</v-alert>
</v-card>
<v-alert v-else-if="scope=='app'" density="compact" color="primary" variant="text" class="mt-10">
<p>
App wide override for the various system prompts based on action type.
</p>
<p class="text-caption text-grey">
These will be used when there are no client specific overrides configured in the client.
</p>
</v-alert>
<v-alert v-else-if="scope=='app'" color="grey" variant="text" class="mt-10">Select a system prompt to edit</v-alert>
<v-alert v-else-if="scope=='client'" density="compact" color="primary" variant="text" class="mt-10">
<p>

View File

@@ -17,6 +17,11 @@
old modal's card surface — on the bare viewport background their
internal surfaces read as disconnected grey islands -->
<v-sheet class="app-settings-content pa-4" rounded="md">
<!-- the page header for every page — page components carry none of their own -->
<AppSettingsPageHeader v-if="currentPage" :title="currentPage.title" :icon="currentPage.icon">
<div v-if="currentPage.descriptionHtml" v-html="currentPage.descriptionHtml"></div>
<template v-else>{{ currentPage.description }}</template>
</AppSettingsPageHeader>
<v-window v-model="page" :touch="false">
<v-window-item value="gameplay">
<AppSettingsGameplay :config="app_config" />
@@ -25,15 +30,9 @@
<AppSettingsPlayerCharacter :config="app_config" />
</v-window-item>
<v-window-item value="appearance-messages">
<AppSettingsPageHeader title="Messages" icon="mdi-script-text">
Style the different message types in the scene view. Changes preview live in the scene while you edit.
</AppSettingsPageHeader>
<AppConfigAppearanceScene ref="appearance-messages" :immutableConfig="app_config" :sceneActive="sceneActive" @changed="onAppearanceChanged"></AppConfigAppearanceScene>
</v-window-item>
<v-window-item value="appearance-visuals">
<AppSettingsPageHeader title="Visuals" icon="mdi-image-outline">
Message visuals and scene backdrop behavior.
</AppSettingsPageHeader>
<AppConfigAppearanceAssets ref="appearance-visuals" :immutableConfig="app_config" :sceneActive="sceneActive" @changed="onAppearanceChanged"></AppConfigAppearanceAssets>
</v-window-item>
<v-window-item value="api-keys">
@@ -67,22 +66,16 @@
</v-window-item>
<v-window-item value="content-classification">
<AppSettingsStringList
title="Content Classification"
icon="mdi-cube-scan"
input-label="Add content classification (Press enter to add)"
:list="app_config.creator.content_context"
@update:list="(list) => app_config.creator.content_context = list">
Available content classification choices when generating characters or scenarios.
</AppSettingsStringList>
</v-window-item>
<v-window-item value="perspective-presets">
<AppSettingsStringList
title="Perspective Presets"
icon="mdi-eye-outline"
input-label="Add perspective preset (Press enter to add)"
:list="app_config.creator.perspective_presets"
@update:list="(list) => app_config.creator.perspective_presets = list">
Reusable narrative perspective / tense strings offered in the scene outline. Use <code>{player_name}</code> as a placeholder for the player character it will be substituted at prompt render time.
</AppSettingsStringList>
</v-window-item>
</v-window>

View File

@@ -1,7 +1,4 @@
<template>
<AppSettingsPageHeader title="API Keys" icon="mdi-key-variant">
API keys and access tokens for third party services. Only fill in the services you use.
</AppSettingsPageHeader>
<v-card v-for="provider in providers" :key="provider.id" class="mb-3" variant="tonal" :data-setting-anchor="provider.id">
<v-card-title class="text-subtitle-1">
<v-icon start size="small">{{ provider.icon || 'mdi-api' }}</v-icon>
@@ -36,14 +33,10 @@
</template>
<script>
import AppSettingsPageHeader from './AppSettingsPageHeader.vue';
import { API_PROVIDERS } from '../utils/appSettingsRegistry.js';
export default {
name: 'AppSettingsApiKeys',
components: {
AppSettingsPageHeader,
},
props: {
config: Object,
},

View File

@@ -1,13 +1,5 @@
<template>
<AppSettingsPageHeader title="Environment Variables" icon="mdi-variable">
<p class="mb-1">Named values passed as environment variables to processes Talemate spawns currently the <span class="text-primary">Pi Bridge</span> client, where pi's <code>models.json</code> can reference them as <code>$NAME</code>.</p>
Values are encrypted at rest in Talemate's configuration file.
</AppSettingsPageHeader>
<v-card variant="tonal">
<v-card-title class="text-subtitle-1">
<v-icon start size="small">mdi-variable</v-icon>
Variables
</v-card-title>
<v-card-text>
<div v-if="envVariableNames.length === 0" class="text-grey text-body-2 mb-4">
No environment variables defined yet add one below.
@@ -44,13 +36,8 @@
</template>
<script>
import AppSettingsPageHeader from './AppSettingsPageHeader.vue';
export default {
name: 'AppSettingsEnvVariables',
components: {
AppSettingsPageHeader,
},
props: {
config: Object,
},

View File

@@ -1,7 +1,4 @@
<template>
<AppSettingsPageHeader title="General" icon="mdi-cog">
General game behavior.
</AppSettingsPageHeader>
<v-row>
<v-col cols="12" data-setting-anchor="auto_save">
<v-checkbox color="primary" v-model="config.game.general.auto_save" label="Auto save" messages="Automatically save after each game-loop"></v-checkbox>
@@ -30,13 +27,8 @@
</template>
<script>
import AppSettingsPageHeader from './AppSettingsPageHeader.vue';
export default {
name: 'AppSettingsGameplay',
components: {
AppSettingsPageHeader,
},
props: {
config: Object,
},

View File

@@ -1,7 +1,4 @@
<template>
<AppSettingsPageHeader title="Default player character" icon="mdi-human-edit">
This will be default player character that will be added to a scene if the scene does not come with a defined player character. Mostly relevant when you load character-cards that aren't in the talemate scene format.
</AppSettingsPageHeader>
<v-row>
<v-col cols="6">
<v-text-field v-model="config.game.default_player_character.name"
@@ -26,13 +23,8 @@
</template>
<script>
import AppSettingsPageHeader from './AppSettingsPageHeader.vue';
export default {
name: 'AppSettingsPlayerCharacter',
components: {
AppSettingsPageHeader,
},
props: {
config: Object,
},

View File

@@ -1,7 +1,4 @@
<template>
<AppSettingsPageHeader :title="title" :icon="icon">
<slot></slot>
</AppSettingsPageHeader>
<v-row>
<v-col cols="12">
<v-list density="compact">
@@ -17,16 +14,9 @@
</template>
<script>
import AppSettingsPageHeader from './AppSettingsPageHeader.vue';
export default {
name: 'AppSettingsStringList',
components: {
AppSettingsPageHeader,
},
props: {
title: String,
icon: String,
inputLabel: String,
list: Array,
},

View File

@@ -5,6 +5,12 @@
// the settings search in the drawer menu. An entry's optional `anchor` matches
// a `data-setting-anchor` attribute in the page markup so search results can
// scroll to and highlight the exact setting.
//
// `title`, `icon` and `description` are also what AppSettings.vue renders as
// the page header — page components must not carry headers of their own. A page
// whose description needs markup adds `descriptionHtml`, which the header
// renders instead; `description` still carries the same words in plain text
// because the search haystack is built from it.
// API key providers rendered by AppSettingsApiKeys.vue. `id` doubles as the
// legacy deep-link page value (`openAppConfig('application', '<id>')`) and the
@@ -121,7 +127,7 @@ export const SETTINGS_GROUPS = [
id: 'player-character',
title: 'Player Character',
icon: 'mdi-human-edit',
description: 'Default player character for scenes that do not define one.',
description: 'The default player character added to a scene when the scene does not come with a defined player character. Mostly relevant when you load character cards that aren\'t in the talemate scene format.',
entries: [
{ label: 'Name', keywords: ['player', 'character', 'default'] },
{ label: 'Gender', keywords: ['player', 'character'] },
@@ -139,7 +145,7 @@ export const SETTINGS_GROUPS = [
id: 'appearance-messages',
title: 'Messages',
icon: 'mdi-script-text',
description: 'Message styles and colors in the scene view.',
description: 'Style the different message types in the scene view. Changes preview live in the scene while you edit.',
entries: [
{ label: 'Message styles', keywords: ['color', 'italic', 'bold', 'narrator', 'character', 'director', 'font'] },
{ label: 'Quotes / emphasis styling', keywords: ['quotes', 'parentheses', 'brackets', 'emphasis', 'entities', 'highlight'] },
@@ -167,7 +173,7 @@ export const SETTINGS_GROUPS = [
id: 'api-keys',
title: 'API Keys',
icon: 'mdi-key-variant',
description: 'API keys for third party services.',
description: 'API keys and access tokens for third party services. Only fill in the services you use.',
entries: API_PROVIDERS.map((provider) => ({
label: provider.title,
anchor: provider.id,
@@ -178,7 +184,8 @@ export const SETTINGS_GROUPS = [
id: 'env-variables',
title: 'Environment Variables',
icon: 'mdi-variable',
description: 'Named values passed to processes Talemate spawns.',
description: 'Named values passed as environment variables to processes Talemate spawns — currently the Pi Bridge client, where pi\'s models.json can reference them as $NAME. Values are encrypted at rest in Talemate\'s configuration file.',
descriptionHtml: '<p class="mb-1">Named values passed as environment variables to processes Talemate spawns — currently the <span class="text-primary">Pi Bridge</span> client, where pi\'s <code>models.json</code> can reference them as <code>$NAME</code>.</p>Values are encrypted at rest in Talemate\'s configuration file.',
entries: [
{ label: 'Environment variables', keywords: ['env', 'secret', 'pi bridge', 'variable'] },
],
@@ -211,7 +218,7 @@ export const SETTINGS_GROUPS = [
id: 'presets-system-prompts',
title: 'System Prompts',
icon: 'mdi-text-box',
description: 'Global system prompt overrides.',
description: 'App wide overrides for the various system prompts, based on action type. Used when the client itself defines no override.',
entries: [
{ label: 'System prompts', keywords: ['prompt', 'roleplay', 'override', 'decensor'] },
],
@@ -226,7 +233,7 @@ export const SETTINGS_GROUPS = [
id: 'content-classification',
title: 'Content Classification',
icon: 'mdi-cube-scan',
description: 'Content classification choices for generation.',
description: 'Available content classification choices when generating characters or scenarios.',
entries: [
{ label: 'Content classification', keywords: ['content context', 'rating', 'classification'] },
],
@@ -235,7 +242,8 @@ export const SETTINGS_GROUPS = [
id: 'perspective-presets',
title: 'Perspective Presets',
icon: 'mdi-eye-outline',
description: 'Reusable narrative perspective / tense strings.',
description: 'Reusable narrative perspective / tense strings offered in the scene outline. Use {player_name} as a placeholder for the player character — it will be substituted at prompt render time.',
descriptionHtml: 'Reusable narrative perspective / tense strings offered in the scene outline. Use <code>{player_name}</code> as a placeholder for the player character — it will be substituted at prompt render time.',
entries: [
{ label: 'Perspective presets', keywords: ['perspective', 'tense', 'pov', 'narrative'] },
],