Add French translate
Add French translation and localize hardcoded strings :
Changes
1. Translation Files
Created
src/i18n/fr.json
: Contains all French translations for the extension.
Updated
src/i18n/en.json
: Added new keys for terms that were previously hardcoded (e.g., "Force", "Volonté", "Météo", "Locked", "Unlocked").
2. UI Updates
settings.html
: Added "Français" to the language selection dropdown.
3. Code Refactoring
src/systems/rendering/thoughts.js
: Replaced hardcoded strings ("Add Character", "Locked", "Click to edit") with i18n calls.
src/systems/rendering/userStats.js
: Replaced hardcoded tooltips and titles with i18n calls.
src/systems/rendering/infoBox.js
: Localized weather, location, and date widget texts.
src/systems/ui/trackerEditor.js
: Updated the "Reset to Defaults" logic to use localized names for stats (e.g., "Santé", "Force") based on the active language.
This commit is contained in:
+14
-6
@@ -16,26 +16,33 @@
|
|||||||
<option value="en" data-i18n-key="settings.language.option.en">English</option>
|
<option value="en" data-i18n-key="settings.language.option.en">English</option>
|
||||||
<option value="zh-tw" data-i18n-key="settings.language.option.zh-tw">繁體中文</option>
|
<option value="zh-tw" data-i18n-key="settings.language.option.zh-tw">繁體中文</option>
|
||||||
<option value="ru" data-i18n-key="settings.language.option.ru">Русский</option>
|
<option value="ru" data-i18n-key="settings.language.option.ru">Русский</option>
|
||||||
|
<option value="fr" data-i18n-key="settings.language.option.fr">Français</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<small class="notes" data-i18n-key="settings.note">Toggle to enable/disable the RPG Companion extension. Configure additional settings within the panel itself.</small>
|
<small class="notes" data-i18n-key="settings.note">Toggle to enable/disable the RPG Companion extension.
|
||||||
|
Configure additional settings within the panel itself.</small>
|
||||||
|
|
||||||
<div style="margin-top: 10px; display: flex; gap: 10px;">
|
<div style="margin-top: 10px; display: flex; gap: 10px;">
|
||||||
<a href="https://discord.com/invite/KdAkTg94ME" target="_blank" class="menu_button" style="flex: 1; text-align: center; text-decoration: none;">
|
<a href="https://discord.com/invite/KdAkTg94ME" target="_blank" class="menu_button"
|
||||||
|
style="flex: 1; text-align: center; text-decoration: none;">
|
||||||
<i class="fa-brands fa-discord"></i> Discord
|
<i class="fa-brands fa-discord"></i> Discord
|
||||||
</a>
|
</a>
|
||||||
<a href="https://ko-fi.com/marinara_spaghetti" target="_blank" class="menu_button" style="flex: 1; text-align: center; text-decoration: none;">
|
<a href="https://ko-fi.com/marinara_spaghetti" target="_blank" class="menu_button"
|
||||||
|
style="flex: 1; text-align: center; text-decoration: none;">
|
||||||
<i class="fa-solid fa-heart"></i> Support
|
<i class="fa-solid fa-heart"></i> Support
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-top: 15px; text-align: center; opacity: 0.7; font-size: 0.8em; line-height: 1.5;">
|
<div style="margin-top: 15px; text-align: center; opacity: 0.7; font-size: 0.8em; line-height: 1.5;">
|
||||||
<div style="margin-bottom: 5px;">
|
<div style="margin-bottom: 5px;">
|
||||||
<i class="fa-solid fa-microchip"></i> <strong data-i18n="settings.recommendedModels.title">Recommended Models:</strong>
|
<i class="fa-solid fa-microchip"></i> <strong
|
||||||
|
data-i18n="settings.recommendedModels.title">Recommended Models:</strong>
|
||||||
</div>
|
</div>
|
||||||
<div style="opacity: 0.8; font-size: 0.9em;" data-i18n="settings.recommendedModels.description">
|
<div style="opacity: 0.8; font-size: 0.9em;" data-i18n="settings.recommendedModels.description">
|
||||||
For the extension to work properly, <strong>it is not recommended to use any models below 20B, especially if they're old.</strong> It works best with the SOTA models such as Deepseek, Claude, GPT, or Gemini.
|
For the extension to work properly, <strong>it is not recommended to use any models below 20B,
|
||||||
|
especially if they're old.</strong> It works best with the SOTA models such as Deepseek, Claude,
|
||||||
|
GPT, or Gemini.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -44,7 +51,8 @@
|
|||||||
<i class="fa-solid fa-users"></i> <strong>Contributors:</strong>
|
<i class="fa-solid fa-users"></i> <strong>Contributors:</strong>
|
||||||
</div>
|
</div>
|
||||||
<div style="opacity: 0.8; font-size: 0.9em;">
|
<div style="opacity: 0.8; font-size: 0.9em;">
|
||||||
SpicyMarinara, Paperboygold, Munimunigamer, Subarashimo, Lilminzyu, Claude, IDeathByte, Chungchandev, Joenunezb, Amauragis, Tomt610, and Jakstein.
|
SpicyMarinara, Paperboygold, Munimunigamer, Subarashimo, Lilminzyu, Claude, IDeathByte,
|
||||||
|
Chungchandev, Joenunezb, Amauragis, Tomt610, and Jakstein.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+39
-5
@@ -182,10 +182,10 @@
|
|||||||
"global.listView": "List view",
|
"global.listView": "List view",
|
||||||
"global.gridView": "Grid view",
|
"global.gridView": "Grid view",
|
||||||
"global.save": "Save",
|
"global.save": "Save",
|
||||||
"global.status":"Status",
|
"global.status": "Status",
|
||||||
"global.inventory":"Inventory",
|
"global.inventory": "Inventory",
|
||||||
"global.quests":"Quests",
|
"global.quests": "Quests",
|
||||||
"global.info":"Info",
|
"global.info": "Info",
|
||||||
"infobox.noData.title": "No data yet",
|
"infobox.noData.title": "No data yet",
|
||||||
"infobox.noData.instruction": "Generate a new response in the roleplay or switch to \"Separate Generation\" in Settings to access and click the \"Refresh RPG Info\" button",
|
"infobox.noData.instruction": "Generate a new response in the roleplay or switch to \"Separate Generation\" in Settings to access and click the \"Refresh RPG Info\" button",
|
||||||
"infobox.recentEvents.title": "Recent Events",
|
"infobox.recentEvents.title": "Recent Events",
|
||||||
@@ -238,5 +238,39 @@
|
|||||||
"musicPlayer.noMusic": "AI will suggest music when appropriate for the scene",
|
"musicPlayer.noMusic": "AI will suggest music when appropriate for the scene",
|
||||||
"errors.parsingError": "RPG Companion Trackers' parsing error! The model returned an incorrect format. If the issue persists, consider changing the model for generations.",
|
"errors.parsingError": "RPG Companion Trackers' parsing error! The model returned an incorrect format. If the issue persists, consider changing the model for generations.",
|
||||||
"settings.recommendedModels.title": "Recommended Models",
|
"settings.recommendedModels.title": "Recommended Models",
|
||||||
"settings.recommendedModels.description": "For the extension to work properly, **it is not recommended to use any models below 20B, especially if they're old.** It works best with the SOTA models such as Deepseek, Claude, GPT, or Gemini."
|
"settings.recommendedModels.description": "For the extension to work properly, **it is not recommended to use any models below 20B, especially if they're old.** It works best with the SOTA models such as Deepseek, Claude, GPT, or Gemini.",
|
||||||
|
"thoughts.addCharacter": "Add Character",
|
||||||
|
"thoughts.locked": "Locked",
|
||||||
|
"thoughts.unlocked": "Unlocked",
|
||||||
|
"thoughts.clickToEdit": "Click to edit",
|
||||||
|
"thoughts.clickToUpload": "Click to upload avatar",
|
||||||
|
"thoughts.removeCharacter": "Remove character",
|
||||||
|
"userStats.level": "LVL",
|
||||||
|
"userStats.clickToEditLevel": "Click to edit level",
|
||||||
|
"userStats.statsLocked": "Locked - AI cannot change stats",
|
||||||
|
"userStats.statsUnlocked": "Unlocked - AI can change stats",
|
||||||
|
"userStats.clickToEditStatName": "Click to edit stat name",
|
||||||
|
"userStats.clickToEditStatValue": "Click to edit",
|
||||||
|
"userStats.moodLocked": "Locked - AI cannot change mood",
|
||||||
|
"userStats.moodUnlocked": "Unlocked - AI can change mood",
|
||||||
|
"userStats.clickToEditEmoji": "Click to edit emoji",
|
||||||
|
"userStats.skillsLocked": "Locked - AI cannot change skills",
|
||||||
|
"userStats.skillsUnlocked": "Unlocked - AI can change skills",
|
||||||
|
"userStats.clickToEditSkills": "Click to edit skills",
|
||||||
|
"infoBox.clickToEdit": "Click to edit",
|
||||||
|
"infoBox.locked": "Locked - AI cannot change this",
|
||||||
|
"infoBox.unlocked": "Unlocked - AI can change this",
|
||||||
|
"infoBox.weatherFallback": "Weather",
|
||||||
|
"infoBox.locationFallback": "Location",
|
||||||
|
"stats.health": "Health",
|
||||||
|
"stats.satiety": "Satiety",
|
||||||
|
"stats.energy": "Energy",
|
||||||
|
"stats.hygiene": "Hygiene",
|
||||||
|
"stats.arousal": "Arousal",
|
||||||
|
"stats.str": "STR",
|
||||||
|
"stats.dex": "DEX",
|
||||||
|
"stats.con": "CON",
|
||||||
|
"stats.int": "INT",
|
||||||
|
"stats.wis": "WIS",
|
||||||
|
"stats.cha": "CHA"
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
{
|
||||||
|
"settings.language.label": "Langue",
|
||||||
|
"settings.language.option.en": "English",
|
||||||
|
"settings.language.option.zh-tw": "繁體中文",
|
||||||
|
"settings.language.option.ru": "Русский",
|
||||||
|
"settings.language.option.fr": "Français",
|
||||||
|
"settings.extensionEnabled": "Activer RPG Companion",
|
||||||
|
"settings.note": "Basculez pour activer/désactiver l'extension RPG Companion. Configurez des paramètres supplémentaires dans le panneau lui-même.",
|
||||||
|
"template.settingsTitle": "Paramètres RPG Companion",
|
||||||
|
"template.settingsModal.themeTitle": "Thème",
|
||||||
|
"template.settingsModal.themeLabel": "Thème Visuel :",
|
||||||
|
"template.settingsModal.themeOptions.default": "Défaut",
|
||||||
|
"template.settingsModal.themeOptions.sciFi": "Sci-Fi (Synthwave)",
|
||||||
|
"template.settingsModal.themeOptions.fantasy": "Fantasy (Parchemin Rustique)",
|
||||||
|
"template.settingsModal.themeOptions.cyberpunk": "Cyberpunk (Grille Néon)",
|
||||||
|
"template.settingsModal.themeOptions.custom": "Personnalisé",
|
||||||
|
"template.settingsModal.themeOptions.custom.background": "Arrière-plan :",
|
||||||
|
"template.settingsModal.themeOptions.custom.accent": "Accent :",
|
||||||
|
"template.settingsModal.themeOptions.custom.text": "Texte :",
|
||||||
|
"template.settingsModal.themeOptions.custom.highlight": "Surlignage :",
|
||||||
|
"template.settingsModal.theme.statBarLow": "Couleur Barre Stat (Bas) :",
|
||||||
|
"template.settingsModal.theme.statBarLowNote": "Couleur lorsque les stats sont à 0%.",
|
||||||
|
"template.settingsModal.theme.statBarHigh": "Couleur Barre Stat (Haut) :",
|
||||||
|
"template.settingsModal.theme.statBarHighNote": "Couleur lorsque les stats sont à 100%.",
|
||||||
|
"template.settingsModal.displayTitle": "Options d'Affichage",
|
||||||
|
"template.settingsModal.displayNote": "Vous pouvez activer/désactiver l'extension complète RPG Companion dans l'onglet Extensions de SillyTavern.",
|
||||||
|
"template.settingsModal.display.panelPosition": "Position du Panneau :",
|
||||||
|
"template.settingsModal.display.panelPositionOptions.right": "Barre Latérale Droite",
|
||||||
|
"template.settingsModal.display.panelPositionOptions.left": "Barre Latérale Gauche",
|
||||||
|
"template.settingsModal.display.toggleAutoUpdate": "Mise à jour auto après messages",
|
||||||
|
"template.settingsModal.display.toggleAutoUpdateNote": "Rafraîchir automatiquement les infos RPG après chaque message.",
|
||||||
|
"template.settingsModal.display.showUserStats": "Afficher Stats Utilisateur",
|
||||||
|
"template.settingsModal.display.showUserStatsNote": "Activer les Stats Utilisateur pour suivre les statistiques, l'humeur, les attributs, les compétences, etc. de votre persona.",
|
||||||
|
"template.settingsModal.display.showInfoBox": "Afficher Boîte Info",
|
||||||
|
"template.settingsModal.display.showInfoBoxNote": "Afficher le lieu, l'heure, la météo et les événements récents.",
|
||||||
|
"template.settingsModal.display.showPresentCharacters": "Afficher Personnages Présents",
|
||||||
|
"template.settingsModal.display.showPresentCharactersNote": "Afficher les portraits des personnages avec leurs pensées actuelles et leur statut.",
|
||||||
|
"template.settingsModal.display.narratorMode": "Mode Narrateur",
|
||||||
|
"template.settingsModal.display.narratorModeNote": "Utiliser la carte de personnage comme narrateur. Déduire les personnages du contexte au lieu d'utiliser des références de personnages fixes.",
|
||||||
|
"template.settingsModal.display.showInventory": "Afficher Inventaire",
|
||||||
|
"template.settingsModal.display.showInventoryNote": "Suivre les objets transportés, les vêtements portés, les objets stockés et les biens.",
|
||||||
|
"template.settingsModal.display.showQuests": "Afficher Quêtes",
|
||||||
|
"template.settingsModal.display.showQuestsNote": "Gérer les quêtes principales et optionnelles avec des objectifs.",
|
||||||
|
"template.settingsModal.display.showLockIcons": "Afficher Icônes Verrouillage",
|
||||||
|
"template.settingsModal.display.showLockIconsNote": "Afficher les icônes de verrouillage/déverrouillage sur les éléments de suivi pour empêcher l'IA de les modifier.",
|
||||||
|
"template.settingsModal.display.showThoughtsInChat": "Afficher Pensées",
|
||||||
|
"template.settingsModal.display.showThoughtsInChatNote": "Afficher les pensées des personnages sous forme de bulles superposées à côté de leurs messages.",
|
||||||
|
"template.settingsModal.display.alwaysShowThoughtBubble": "Toujours Afficher Bulle Pensée",
|
||||||
|
"template.settingsModal.display.alwaysShowThoughtBubbleNote": "Développer automatiquement la bulle de pensée sans cliquer sur l'icône d'abord",
|
||||||
|
"template.settingsModal.display.enableAnimations": "Activer Animations",
|
||||||
|
"template.settingsModal.display.enableAnimationsNote": "Transitions fluides pour les stats, les mises à jour de contenu et les lancers de dés.",
|
||||||
|
"template.settingsModal.display.showImmersiveHtmlToggle": "Afficher HTML Immersif",
|
||||||
|
"template.settingsModal.display.showImmersiveHtmlToggleNote": "Afficher un bouton pour activer/désactiver le formatage HTML dans les messages.",
|
||||||
|
"template.settingsModal.display.showDialogueColoringToggle": "Afficher Dialogues Colorés",
|
||||||
|
"template.settingsModal.display.showDialogueColoringToggleNote": "Afficher un bouton pour activer/désactiver le formatage des dialogues colorés.",
|
||||||
|
"template.settingsModal.display.showDeceptionToggle": "Afficher Système Déception",
|
||||||
|
"template.settingsModal.display.showDeceptionToggleNote": "Afficher un bouton pour activer/désactiver le Système de Déception pour marquer les mensonges.",
|
||||||
|
"template.settingsModal.display.showOmniscienceToggle": "Afficher Filtre Omniscience",
|
||||||
|
"template.settingsModal.display.showOmniscienceToggleNote": "Afficher un bouton pour activer/désactiver le Filtre d'Omniscience pour filtrer les événements cachés.",
|
||||||
|
"template.settingsModal.display.showSpotifyMusicToggle": "Afficher Musique Spotify",
|
||||||
|
"template.settingsModal.display.showSpotifyMusicToggleNote": "Afficher le lecteur Spotify avec des pistes suggérées par l'IA appropriées à la scène.",
|
||||||
|
"template.settingsModal.display.showSnowflakesToggle": "Afficher Effet Flocons",
|
||||||
|
"template.settingsModal.display.showDynamicWeatherToggle": "Afficher Effets Météo Dynamiques",
|
||||||
|
"template.settingsModal.display.showDynamicWeatherToggleNote": "Afficher un bouton pour activer/désactiver les effets météo animés.",
|
||||||
|
"template.settingsModal.display.showNarratorMode": "Afficher Mode Narrateur",
|
||||||
|
"template.settingsModal.display.showNarratorModeNote": "Afficher un bouton pour activer/désactiver le mode narrateur (déduire les personnages du contexte).",
|
||||||
|
"template.settingsModal.display.showAutoAvatars": "Afficher Génération Auto Avatars",
|
||||||
|
"template.settingsModal.display.showAutoAvatarsNote": "Afficher un bouton pour générer automatiquement des avatars pour les personnages sans image.",
|
||||||
|
"template.settingsModal.display.showRandomizedPlot": "Afficher Progression Intrigue Aléatoire",
|
||||||
|
"template.settingsModal.display.showRandomizedPlotNote": "Afficher un bouton pour des invites de progression d'intrigue générées aléatoirement par l'IA.",
|
||||||
|
"template.settingsModal.display.showNaturalPlot": "Afficher Progression Intrigue Naturelle",
|
||||||
|
"template.settingsModal.display.showNaturalPlotNote": "Afficher un bouton pour des invites de continuation narrative conscientes du contexte.",
|
||||||
|
"template.settingsModal.display.showStartEncounter": "Afficher Démarrer Rencontre",
|
||||||
|
"template.settingsModal.display.showStartEncounterNote": "Afficher un bouton pour initier des rencontres de combat interactives.",
|
||||||
|
"template.settingsModal.display.showDiceDisplay": "Afficher Lancer de Dés",
|
||||||
|
"template.settingsModal.display.showDiceDisplayNote": "Afficher l'indicateur \"Dernier Lancer\" dans le panneau.",
|
||||||
|
"template.mainPanel.autoAvatars": "Avatars Auto",
|
||||||
|
"template.settingsModal.advancedTitle": "Avancé",
|
||||||
|
"template.settingsModal.advanced.encounterHistoryDepth": "Profondeur Historique Rencontre :",
|
||||||
|
"template.settingsModal.advanced.encounterHistoryDepthNote": "Nombre de messages récents à inclure dans l'initialisation du combat.",
|
||||||
|
"template.settingsModal.advanced.autoSaveCombatLogs": "Sauvegarde Auto Journaux Combat",
|
||||||
|
"template.settingsModal.advanced.autoSaveCombatLogsNote": "Sauvegarder les journaux de combat détaillés dans un fichier pour référence future et analyse.",
|
||||||
|
"template.settingsModal.advanced.clearCacheNote": "Efface les données de suivi validées et affichées pour votre chat actuellement actif.",
|
||||||
|
"template.settingsModal.advanced.generationMode": "Mode de Génération :",
|
||||||
|
"template.settingsModal.advanced.generationModeOptions.together": "Ensemble avec Génération Principale",
|
||||||
|
"template.settingsModal.advanced.generationModeOptions.separate": "Génération Séparée",
|
||||||
|
"template.settingsModal.advanced.generationModeNote": "Ensemble : Ajoute le suivi RPG au jeu de rôle principal. Séparé : Génère les données RPG séparément (manuel ou auto). Externe : Se connecte directement à un point de terminaison compatible OpenAI.",
|
||||||
|
"template.settingsModal.advanced.generationModeOptions.external": "API Externe",
|
||||||
|
"template.settingsModal.advanced.externalApi.title": "Paramètres API Externe",
|
||||||
|
"template.settingsModal.advanced.externalApi.baseUrl": "URL de base API",
|
||||||
|
"template.settingsModal.advanced.externalApi.baseUrlNote": "Point de terminaison compatible OpenAI (ex: OpenAI, OpenRouter, serveur LLM local).",
|
||||||
|
"template.settingsModal.advanced.externalApi.apiKey": "Clé API",
|
||||||
|
"template.settingsModal.advanced.externalApi.apiKeyNote": "Votre clé API pour le service externe.",
|
||||||
|
"template.settingsModal.advanced.externalApi.model": "Modèle",
|
||||||
|
"template.settingsModal.advanced.externalApi.modelNote": "Identifiant du modèle (ex: gpt-4o-mini, claude-3-haiku, mistral-7b).",
|
||||||
|
"template.settingsModal.advanced.externalApi.maxTokens": "Max Tokens",
|
||||||
|
"template.settingsModal.advanced.externalApi.temperature": "Température",
|
||||||
|
"template.settingsModal.advanced.externalApi.testConnection": "Tester Connexion",
|
||||||
|
"template.settingsModal.advanced.contextMessages": "Messages de Contexte :",
|
||||||
|
"template.settingsModal.advanced.contextMessagesNote": "Nombre de messages récents à inclure.",
|
||||||
|
"template.settingsModal.advanced.useSeparatePreset": "Utiliser modèle connecté au preset RPG Companion Trackers",
|
||||||
|
"template.settingsModal.advanced.useSeparatePresetNote": "Si activé, la génération de suivi utilisera le modèle du preset \"RPG Companion Trackers\" au lieu de votre modèle API principal. Le preset sera commuté automatiquement pendant la génération et restauré après. Sélectionnez le modèle souhaité dans ce preset et assurez-vous que l'option \"Lier les presets aux connexions API\" est activée (à côté des boutons import/export preset).",
|
||||||
|
"template.settingsModal.advanced.skipInjections": "Sauter Injections Pendant Générations Guidées :",
|
||||||
|
"template.settingsModal.advanced.skipInjectionsOptions.none": "Ne jamais sauter",
|
||||||
|
"template.settingsModal.advanced.skipInjectionsOptions.impersonation": "Seulement sur demandes d'imitation",
|
||||||
|
"template.settingsModal.advanced.skipInjectionsOptions.guided": "Toujours pour invites guidées ou silencieuses",
|
||||||
|
"template.settingsModal.advanced.skipInjectionsNote": "Si défini, l'extension n'injectera pas les invites de suivi, exemples ou instructions HTML selon le mode sélectionné lorsqu'une génération guidée (via `instruct` ou `quiet_prompt`) est détectée. Utile lors de l'utilisation de GuidedGenerations ou extensions similaires.",
|
||||||
|
"template.settingsModal.advanced.customHtmlPromptTitle": "Invite HTML Personnalisée :",
|
||||||
|
"template.settingsModal.advanced.restoreDefaultHtmlPrompt": "Restaurer Défaut",
|
||||||
|
"template.settingsModal.advanced.customHtmlPromptNote": "Personnalisez l'invite HTML injectée lorsque \"Activer HTML Immersif\" est activé. L'invite par défaut est affichée ci-dessus - vous pouvez l'éditer directement ou la remplacer entièrement. Cliquez sur \"Restaurer Défaut\" pour réinitialiser. Cela affecte tous les modes de génération (ensemble, séparé et progression d'intrigue).",
|
||||||
|
"template.settingsModal.advanced.clearCache": "Effacer Cache Extension",
|
||||||
|
"template.settingsModal.advanced.resetFabPositions": "Réinitialiser Positions Boutons",
|
||||||
|
"template.settingsModal.advanced.resetFabPositionsNote": "Réinitialise tous les boutons d'action flottants (bascule, rafraîchir, debug) à leurs positions par défaut en haut à gauche. Utile si les boutons sont hors écran.",
|
||||||
|
"template.trackerEditorModal.title": "Éditer Suivis",
|
||||||
|
"template.trackerEditorModal.tabs.userStats": "Stats Utilisateur",
|
||||||
|
"template.trackerEditorModal.tabs.infoBox": "Boîte Info",
|
||||||
|
"template.trackerEditorModal.tabs.presentCharacters": "Personnages Présents",
|
||||||
|
"template.trackerEditorModal.buttons.reset": "Réinitialiser",
|
||||||
|
"template.trackerEditorModal.buttons.cancel": "Annuler",
|
||||||
|
"template.trackerEditorModal.buttons.save": "Sauvegarder & Appliquer",
|
||||||
|
"template.trackerEditorModal.buttons.export": "Exporter",
|
||||||
|
"template.trackerEditorModal.buttons.import": "Importer",
|
||||||
|
"template.trackerEditorModal.messages.exportSuccess": "Preset de suivi exporté avec succès !",
|
||||||
|
"template.trackerEditorModal.messages.exportError": "Échec de l'exportation du preset. Vérifiez la console pour les détails.",
|
||||||
|
"template.trackerEditorModal.messages.importSuccess": "Preset de suivi importé avec succès !",
|
||||||
|
"template.trackerEditorModal.messages.importError": "Échec de l'importation du preset",
|
||||||
|
"template.trackerEditorModal.messages.importConfirm": "Ceci remplacera votre configuration actuelle de suivi. Continuer ?",
|
||||||
|
"template.trackerEditorModal.userStatsTab.customStatsTitle": "Stats Personnalisées",
|
||||||
|
"template.trackerEditorModal.userStatsTab.addCustomStatButton": "Ajouter Stat Perso",
|
||||||
|
"template.trackerEditorModal.userStatsTab.rpgAttributesTitle": "Attributs RPG",
|
||||||
|
"template.trackerEditorModal.userStatsTab.enableRpgAttributes": "Activer Section Attributs RPG",
|
||||||
|
"template.trackerEditorModal.userStatsTab.alwaysIncludeAttributes": "Toujours Inclure Attributs dans Invite",
|
||||||
|
"template.trackerEditorModal.userStatsTab.alwaysIncludeAttributesNote": "Si désactivé, les attributs ne sont envoyés que lorsqu'un lancer de dé est actif.",
|
||||||
|
"template.trackerEditorModal.userStatsTab.addAttributeButton": "Ajouter Attribut",
|
||||||
|
"template.trackerEditorModal.userStatsTab.statusSectionTitle": "Section Statut",
|
||||||
|
"template.trackerEditorModal.userStatsTab.enableStatusSection": "Activer Section Statut",
|
||||||
|
"template.trackerEditorModal.userStatsTab.showMoodEmoji": "Afficher Emoji Humeur",
|
||||||
|
"template.trackerEditorModal.userStatsTab.statusFieldsLabel": "Champs Statut (séparés par virgule) :",
|
||||||
|
"template.trackerEditorModal.userStatsTab.skillsSectionTitle": "Section Compétences",
|
||||||
|
"template.trackerEditorModal.userStatsTab.enableSkillsSection": "Activer Section Compétences",
|
||||||
|
"template.trackerEditorModal.userStatsTab.skillsLabelLabel": "Libellé Compétences :",
|
||||||
|
"template.trackerEditorModal.userStatsTab.skillsListLabel": "Liste Compétences (séparées par virgule) :",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.widgetsTitle": "Widgets",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.dateWidget": "Date",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.weatherWidget": "Météo",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.temperatureWidget": "Température",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.timeWidget": "Heure",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.locationWidget": "Lieu",
|
||||||
|
"template.trackerEditorModal.infoBoxTab.recentEventsWidget": "Événements Récents",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.relationshipStatusTitle": "Champs Statut Relation",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.enableRelationshipStatus": "Activer Champs Statut Relation",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.relationshipStatusHint": "Définir les types de relation avec les emojis correspondants affichés sur les portraits des personnages.",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.newRelationshipButton": "Nouvelle Relation",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.appearanceDemeanorTitle": "Champs Apparence/Comportement",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.appearanceDemeanorHint": "Champs affichés sous le nom du personnage.",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.addCustomFieldButton": "Ajouter Champ Perso",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.thoughtsConfigTitle": "Configuration Pensées",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.enableCharacterThoughts": "Activer Pensées Personnage",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.thoughtsLabelLabel": "Libellé Pensées :",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.aiInstructionLabel": "Instruction IA :",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.characterStatsTitle": "Stats Personnage",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.trackCharacterStats": "Suivre Stats Personnage",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.characterStatsHint": "Créer des stats à suivre pour chaque personnage (affichées comme nombres colorés).",
|
||||||
|
"template.trackerEditorModal.presentCharactersTab.addCharacterStatButton": "Ajouter Stat Personnage",
|
||||||
|
"template.mainPanel.title": "RPG Companion",
|
||||||
|
"template.mainPanel.lastRoll": "Dernier Lancer :",
|
||||||
|
"template.mainPanel.clearLastRoll": "Effacer dernier lancer",
|
||||||
|
"template.mainPanel.immersiveHtml": "HTML Immersif",
|
||||||
|
"template.mainPanel.coloredDialogues": "Dialogues Colorés",
|
||||||
|
"template.mainPanel.deceptionSystem": "Système Déception",
|
||||||
|
"template.mainPanel.omniscienceFilter": "Filtre Omniscience",
|
||||||
|
"template.mainPanel.spotifyMusic": "Musique Spotify",
|
||||||
|
"template.mainPanel.snowflakesEffect": "Effet Flocons",
|
||||||
|
"template.mainPanel.dynamicWeatherEffects": "Météo Dynamique",
|
||||||
|
"template.mainPanel.narratorMode": "Mode Narrateur",
|
||||||
|
"template.mainPanel.refreshRpgInfo": "Rafraîchir Infos RPG",
|
||||||
|
"template.mainPanel.updating": "Mise à jour...",
|
||||||
|
"template.mainPanel.editTrackersButton": "Éditer Suivis",
|
||||||
|
"template.mainPanel.settingsButton": "Paramètres",
|
||||||
|
"global.none": "Aucun",
|
||||||
|
"global.add": "Ajouter",
|
||||||
|
"global.cancel": "Annuler",
|
||||||
|
"global.listView": "Vue liste",
|
||||||
|
"global.gridView": "Vue grille",
|
||||||
|
"global.save": "Sauvegarder",
|
||||||
|
"global.status": "Statut",
|
||||||
|
"global.inventory": "Inventaire",
|
||||||
|
"global.quests": "Quêtes",
|
||||||
|
"global.info": "Info",
|
||||||
|
"infobox.noData.title": "Pas de données",
|
||||||
|
"infobox.noData.instruction": "Générez une nouvelle réponse dans le jeu de rôle ou basculez vers \"Génération Séparée\" dans les Paramètres pour accéder et cliquer sur le bouton \"Rafraîchir Infos RPG\"",
|
||||||
|
"infobox.recentEvents.title": "Événements Récents",
|
||||||
|
"infobox.recentEvents.addEventPlaceholder": "Ajouter événement...",
|
||||||
|
"inventory.section.onPerson": "Sur Soi",
|
||||||
|
"inventory.section.clothing": "Vêtements",
|
||||||
|
"inventory.section.stored": "Stocké",
|
||||||
|
"inventory.section.assets": "Biens",
|
||||||
|
"inventory.onPerson.empty": "Aucun objet porté",
|
||||||
|
"inventory.onPerson.title": "Objets Actuellement Portés",
|
||||||
|
"inventory.onPerson.addItemButton": "Ajouter Objet",
|
||||||
|
"inventory.onPerson.addItemPlaceholder": "Entrer nom objet...",
|
||||||
|
"inventory.clothing.empty": "Ne porte rien",
|
||||||
|
"inventory.clothing.title": "Vêtements & Armure",
|
||||||
|
"inventory.clothing.addItemButton": "Ajouter Vêtement",
|
||||||
|
"inventory.clothing.addItemPlaceholder": "Entrer vêtement...",
|
||||||
|
"inventory.stored.title": "Lieux de Stockage",
|
||||||
|
"inventory.stored.addLocationButton": "Ajouter Lieu",
|
||||||
|
"inventory.stored.addLocationPlaceholder": "Entrer nom lieu...",
|
||||||
|
"inventory.stored.saveButton": "Sauvegarder",
|
||||||
|
"inventory.stored.empty": "Aucun lieu de stockage. Cliquez sur \"Ajouter Lieu\" pour en créer un.",
|
||||||
|
"inventory.stored.noItems": "Aucun objet stocké ici",
|
||||||
|
"inventory.stored.addItemToLocationPlaceholder": "Entrer nom objet...",
|
||||||
|
"inventory.stored.addItemButton": "Ajouter Objet",
|
||||||
|
"inventory.stored.confirmRemoveLocationMessage": "Supprimer \"${location}\" ? Cela supprimera tous les objets stockés ici.",
|
||||||
|
"inventory.stored.confirmRemoveLocationConfirmButton": "Confirmer",
|
||||||
|
"inventory.assets.empty": "Aucun bien possédé",
|
||||||
|
"inventory.assets.title": "Véhicules, Propriétés & Possessions Majeures",
|
||||||
|
"inventory.assets.addAssetModalTitle": "Ajouter Bien",
|
||||||
|
"inventory.assets.addAssetButton": "Ajouter Bien",
|
||||||
|
"inventory.assets.addAssetPlaceholder": "Entrer nom bien...",
|
||||||
|
"inventory.assets.description": "Les biens incluent les véhicules (voitures, motos), les propriétés (maisons, appartements) et les équipements majeurs (outils d'atelier, objets spéciaux).",
|
||||||
|
"quests.section.main": "Quête Principale",
|
||||||
|
"quests.section.optional": "Quêtes Optionnelles",
|
||||||
|
"quests.main.title": "Quêtes Principales",
|
||||||
|
"quests.main.addQuestButton": "Ajouter Quête",
|
||||||
|
"quests.main.addQuestPlaceholder": "Entrer titre quête principale...",
|
||||||
|
"quests.main.empty": "Aucune quête principale active",
|
||||||
|
"quests.main.hint": "La quête principale représente votre objectif principal dans l'histoire.",
|
||||||
|
"quests.optional.title": "Quêtes Optionnelles",
|
||||||
|
"quests.optional.addQuestButton": "Ajouter Quête",
|
||||||
|
"quests.optional.addQuestPlaceholder": "Entrer titre quête optionnelle...",
|
||||||
|
"quests.optional.empty": "Aucune quête optionnelle active",
|
||||||
|
"quests.optional.hint": "Les quêtes optionnelles sont des objectifs secondaires qui complètent votre histoire principale.",
|
||||||
|
"checkpoint.setChapterStart": "Définir Début Chapitre",
|
||||||
|
"checkpoint.clearChapterStart": "Effacer Début Chapitre",
|
||||||
|
"checkpoint.indicator": "Début Chapitre",
|
||||||
|
"checkpoint.tooltip": "Les messages avant ce point sont exclus du contexte",
|
||||||
|
"musicPlayer.title": "Musique de Scène",
|
||||||
|
"musicPlayer.noMusic": "L'IA suggérera de la musique quand approprié pour la scène",
|
||||||
|
"errors.parsingError": "Erreur de parsing RPG Companion Trackers ! Le modèle a renvoyé un format incorrect. Si le problème persiste, envisagez de changer le modèle pour les générations.",
|
||||||
|
"settings.recommendedModels.title": "Modèles Recommandés",
|
||||||
|
"settings.recommendedModels.description": "Pour que l'extension fonctionne correctement, **il n'est pas recommandé d'utiliser des modèles de moins de 20B, surtout s'ils sont anciens.** Elle fonctionne mieux avec les modèles SOTA tels que Deepseek, Claude, GPT ou Gemini.",
|
||||||
|
"thoughts.addCharacter": "Ajouter un personnage",
|
||||||
|
"thoughts.locked": "Verrouillé",
|
||||||
|
"thoughts.unlocked": "Déverrouillé",
|
||||||
|
"thoughts.clickToEdit": "Cliquer pour modifier",
|
||||||
|
"thoughts.clickToUpload": "Cliquer pour télécharger un avatar",
|
||||||
|
"thoughts.removeCharacter": "Supprimer le personnage",
|
||||||
|
"userStats.level": "NIV",
|
||||||
|
"userStats.clickToEditLevel": "Cliquer pour modifier le niveau",
|
||||||
|
"userStats.statsLocked": "Verrouillé - L'IA ne peut pas modifier les stats",
|
||||||
|
"userStats.statsUnlocked": "Déverrouillé - L'IA peut modifier les stats",
|
||||||
|
"userStats.clickToEditStatName": "Cliquer pour modifier le nom",
|
||||||
|
"userStats.clickToEditStatValue": "Cliquer pour modifier",
|
||||||
|
"userStats.moodLocked": "Verrouillé - L'IA ne peut pas modifier l'humeur",
|
||||||
|
"userStats.moodUnlocked": "Déverrouillé - L'IA peut modifier l'humeur",
|
||||||
|
"userStats.clickToEditEmoji": "Cliquer pour modifier l'émoji",
|
||||||
|
"userStats.skillsLocked": "Verrouillé - L'IA ne peut pas modifier les compétences",
|
||||||
|
"userStats.skillsUnlocked": "Déverrouillé - L'IA peut modifier les compétences",
|
||||||
|
"userStats.clickToEditSkills": "Cliquer pour modifier les compétences",
|
||||||
|
"infoBox.clickToEdit": "Cliquer pour modifier",
|
||||||
|
"infoBox.locked": "Verrouillé - L'IA ne peut pas modifier à ceci",
|
||||||
|
"infoBox.unlocked": "Déverrouillé - L'IA peut modifier à ceci",
|
||||||
|
"infoBox.weatherFallback": "Météo",
|
||||||
|
"infoBox.locationFallback": "Lieu",
|
||||||
|
"stats.health": "Santé",
|
||||||
|
"stats.satiety": "Satiété",
|
||||||
|
"stats.energy": "Énergie",
|
||||||
|
"stats.hygiene": "Hygiène",
|
||||||
|
"stats.arousal": "Excitation",
|
||||||
|
"stats.str": "FOR",
|
||||||
|
"stats.dex": "DEX",
|
||||||
|
"stats.con": "CON",
|
||||||
|
"stats.int": "INT",
|
||||||
|
"stats.wis": "VOL",
|
||||||
|
"stats.cha": "CHA"
|
||||||
|
}
|
||||||
+168
-168
@@ -159,171 +159,171 @@ export function renderInfoBox() {
|
|||||||
const lines = infoBoxData.split('\n');
|
const lines = infoBoxData.split('\n');
|
||||||
// console.log('[RPG Companion] Info Box split into lines:', lines);
|
// console.log('[RPG Companion] Info Box split into lines:', lines);
|
||||||
|
|
||||||
// Track which fields we've already parsed to avoid duplicates from mixed formats
|
// Track which fields we've already parsed to avoid duplicates from mixed formats
|
||||||
const parsedFields = {
|
const parsedFields = {
|
||||||
date: false,
|
date: false,
|
||||||
temperature: false,
|
temperature: false,
|
||||||
time: false,
|
time: false,
|
||||||
location: false,
|
location: false,
|
||||||
weather: false
|
weather: false
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
// console.log('[RPG Companion] Processing line:', line);
|
// console.log('[RPG Companion] Processing line:', line);
|
||||||
|
|
||||||
// Support both new text format (Date:) and legacy emoji format (🗓️:)
|
// Support both new text format (Date:) and legacy emoji format (🗓️:)
|
||||||
// Prioritize text format over emoji format
|
// Prioritize text format over emoji format
|
||||||
if (line.startsWith('Date:')) {
|
if (line.startsWith('Date:')) {
|
||||||
if (!parsedFields.date) {
|
if (!parsedFields.date) {
|
||||||
// console.log('[RPG Companion] → Matched DATE (text format)');
|
// console.log('[RPG Companion] → Matched DATE (text format)');
|
||||||
const dateStr = line.replace('Date:', '').trim();
|
const dateStr = line.replace('Date:', '').trim();
|
||||||
const dateParts = dateStr.split(',').map(p => p.trim());
|
const dateParts = dateStr.split(',').map(p => p.trim());
|
||||||
data.weekday = dateParts[0] || '';
|
data.weekday = dateParts[0] || '';
|
||||||
data.month = dateParts[1] || '';
|
data.month = dateParts[1] || '';
|
||||||
data.year = dateParts[2] || '';
|
data.year = dateParts[2] || '';
|
||||||
data.date = dateStr;
|
data.date = dateStr;
|
||||||
parsedFields.date = true;
|
parsedFields.date = true;
|
||||||
}
|
|
||||||
} else if (line.includes('🗓️:')) {
|
|
||||||
if (!parsedFields.date) {
|
|
||||||
// console.log('[RPG Companion] → Matched DATE (emoji format)');
|
|
||||||
const dateStr = line.replace('🗓️:', '').trim();
|
|
||||||
const dateParts = dateStr.split(',').map(p => p.trim());
|
|
||||||
data.weekday = dateParts[0] || '';
|
|
||||||
data.month = dateParts[1] || '';
|
|
||||||
data.year = dateParts[2] || '';
|
|
||||||
data.date = dateStr;
|
|
||||||
parsedFields.date = true;
|
|
||||||
}
|
|
||||||
} else if (line.startsWith('Temperature:')) {
|
|
||||||
if (!parsedFields.temperature) {
|
|
||||||
// console.log('[RPG Companion] → Matched TEMPERATURE (text format)');
|
|
||||||
const tempStr = line.replace('Temperature:', '').trim();
|
|
||||||
data.temperature = tempStr;
|
|
||||||
const tempMatch = tempStr.match(/(-?\d+)/);
|
|
||||||
if (tempMatch) {
|
|
||||||
data.tempValue = parseInt(tempMatch[1]);
|
|
||||||
}
|
}
|
||||||
parsedFields.temperature = true;
|
} else if (line.includes('🗓️:')) {
|
||||||
}
|
if (!parsedFields.date) {
|
||||||
} else if (line.includes('🌡️:')) {
|
// console.log('[RPG Companion] → Matched DATE (emoji format)');
|
||||||
if (!parsedFields.temperature) {
|
const dateStr = line.replace('🗓️:', '').trim();
|
||||||
// console.log('[RPG Companion] → Matched TEMPERATURE (emoji format)');
|
const dateParts = dateStr.split(',').map(p => p.trim());
|
||||||
const tempStr = line.replace('🌡️:', '').trim();
|
data.weekday = dateParts[0] || '';
|
||||||
data.temperature = tempStr;
|
data.month = dateParts[1] || '';
|
||||||
const tempMatch = tempStr.match(/(-?\d+)/);
|
data.year = dateParts[2] || '';
|
||||||
if (tempMatch) {
|
data.date = dateStr;
|
||||||
data.tempValue = parseInt(tempMatch[1]);
|
parsedFields.date = true;
|
||||||
}
|
}
|
||||||
parsedFields.temperature = true;
|
} else if (line.startsWith('Temperature:')) {
|
||||||
}
|
if (!parsedFields.temperature) {
|
||||||
} else if (line.startsWith('Time:')) {
|
// console.log('[RPG Companion] → Matched TEMPERATURE (text format)');
|
||||||
if (!parsedFields.time) {
|
const tempStr = line.replace('Temperature:', '').trim();
|
||||||
// console.log('[RPG Companion] → Matched TIME (text format)');
|
data.temperature = tempStr;
|
||||||
const timeStr = line.replace('Time:', '').trim();
|
const tempMatch = tempStr.match(/(-?\d+)/);
|
||||||
data.time = timeStr;
|
if (tempMatch) {
|
||||||
const timeParts = timeStr.split('→').map(t => t.trim());
|
data.tempValue = parseInt(tempMatch[1]);
|
||||||
data.timeStart = timeParts[0] || '';
|
}
|
||||||
data.timeEnd = timeParts[1] || '';
|
parsedFields.temperature = true;
|
||||||
parsedFields.time = true;
|
|
||||||
}
|
|
||||||
} else if (line.includes('🕒:')) {
|
|
||||||
if (!parsedFields.time) {
|
|
||||||
// console.log('[RPG Companion] → Matched TIME (emoji format)');
|
|
||||||
const timeStr = line.replace('🕒:', '').trim();
|
|
||||||
data.time = timeStr;
|
|
||||||
const timeParts = timeStr.split('→').map(t => t.trim());
|
|
||||||
data.timeStart = timeParts[0] || '';
|
|
||||||
data.timeEnd = timeParts[1] || '';
|
|
||||||
parsedFields.time = true;
|
|
||||||
}
|
|
||||||
} else if (line.startsWith('Location:')) {
|
|
||||||
if (!parsedFields.location) {
|
|
||||||
// console.log('[RPG Companion] → Matched LOCATION (text format)');
|
|
||||||
data.location = line.replace('Location:', '').trim();
|
|
||||||
parsedFields.location = true;
|
|
||||||
}
|
|
||||||
} else if (line.includes('🗺️:')) {
|
|
||||||
if (!parsedFields.location) {
|
|
||||||
// console.log('[RPG Companion] → Matched LOCATION (emoji format)');
|
|
||||||
data.location = line.replace('🗺️:', '').trim();
|
|
||||||
parsedFields.location = true;
|
|
||||||
}
|
|
||||||
} else if (line.startsWith('Weather:')) {
|
|
||||||
if (!parsedFields.weather) {
|
|
||||||
// New text format: Weather: [Emoji], [Forecast] OR Weather: [Emoji][Forecast] (no separator - FIXED)
|
|
||||||
const weatherStr = line.replace('Weather:', '').trim();
|
|
||||||
const { emoji, text } = separateEmojiFromText(weatherStr);
|
|
||||||
|
|
||||||
if (emoji && text) {
|
|
||||||
data.weatherEmoji = emoji;
|
|
||||||
data.weatherForecast = text;
|
|
||||||
} else if (weatherStr.includes(',')) {
|
|
||||||
// Fallback to comma split if emoji detection failed - split only on FIRST comma
|
|
||||||
const firstCommaIndex = weatherStr.indexOf(',');
|
|
||||||
data.weatherEmoji = weatherStr.substring(0, firstCommaIndex).trim();
|
|
||||||
data.weatherForecast = weatherStr.substring(firstCommaIndex + 1).trim();
|
|
||||||
} else {
|
|
||||||
// No clear separation - assume it's all forecast text
|
|
||||||
data.weatherEmoji = '🌤️'; // Default emoji
|
|
||||||
data.weatherForecast = weatherStr;
|
|
||||||
}
|
}
|
||||||
|
} else if (line.includes('🌡️:')) {
|
||||||
|
if (!parsedFields.temperature) {
|
||||||
|
// console.log('[RPG Companion] → Matched TEMPERATURE (emoji format)');
|
||||||
|
const tempStr = line.replace('🌡️:', '').trim();
|
||||||
|
data.temperature = tempStr;
|
||||||
|
const tempMatch = tempStr.match(/(-?\d+)/);
|
||||||
|
if (tempMatch) {
|
||||||
|
data.tempValue = parseInt(tempMatch[1]);
|
||||||
|
}
|
||||||
|
parsedFields.temperature = true;
|
||||||
|
}
|
||||||
|
} else if (line.startsWith('Time:')) {
|
||||||
|
if (!parsedFields.time) {
|
||||||
|
// console.log('[RPG Companion] → Matched TIME (text format)');
|
||||||
|
const timeStr = line.replace('Time:', '').trim();
|
||||||
|
data.time = timeStr;
|
||||||
|
const timeParts = timeStr.split('→').map(t => t.trim());
|
||||||
|
data.timeStart = timeParts[0] || '';
|
||||||
|
data.timeEnd = timeParts[1] || '';
|
||||||
|
parsedFields.time = true;
|
||||||
|
}
|
||||||
|
} else if (line.includes('🕒:')) {
|
||||||
|
if (!parsedFields.time) {
|
||||||
|
// console.log('[RPG Companion] → Matched TIME (emoji format)');
|
||||||
|
const timeStr = line.replace('🕒:', '').trim();
|
||||||
|
data.time = timeStr;
|
||||||
|
const timeParts = timeStr.split('→').map(t => t.trim());
|
||||||
|
data.timeStart = timeParts[0] || '';
|
||||||
|
data.timeEnd = timeParts[1] || '';
|
||||||
|
parsedFields.time = true;
|
||||||
|
}
|
||||||
|
} else if (line.startsWith('Location:')) {
|
||||||
|
if (!parsedFields.location) {
|
||||||
|
// console.log('[RPG Companion] → Matched LOCATION (text format)');
|
||||||
|
data.location = line.replace('Location:', '').trim();
|
||||||
|
parsedFields.location = true;
|
||||||
|
}
|
||||||
|
} else if (line.includes('🗺️:')) {
|
||||||
|
if (!parsedFields.location) {
|
||||||
|
// console.log('[RPG Companion] → Matched LOCATION (emoji format)');
|
||||||
|
data.location = line.replace('🗺️:', '').trim();
|
||||||
|
parsedFields.location = true;
|
||||||
|
}
|
||||||
|
} else if (line.startsWith('Weather:')) {
|
||||||
|
if (!parsedFields.weather) {
|
||||||
|
// New text format: Weather: [Emoji], [Forecast] OR Weather: [Emoji][Forecast] (no separator - FIXED)
|
||||||
|
const weatherStr = line.replace('Weather:', '').trim();
|
||||||
|
const { emoji, text } = separateEmojiFromText(weatherStr);
|
||||||
|
|
||||||
parsedFields.weather = true;
|
if (emoji && text) {
|
||||||
}
|
data.weatherEmoji = emoji;
|
||||||
} else {
|
data.weatherForecast = text;
|
||||||
// Check if it's a legacy weather line (emoji format)
|
} else if (weatherStr.includes(',')) {
|
||||||
// Only parse if we haven't already found weather in text format
|
// Fallback to comma split if emoji detection failed - split only on FIRST comma
|
||||||
if (!parsedFields.weather) {
|
const firstCommaIndex = weatherStr.indexOf(',');
|
||||||
// Since \p{Emoji} doesn't work reliably, use a simpler approach
|
data.weatherEmoji = weatherStr.substring(0, firstCommaIndex).trim();
|
||||||
const hasColon = line.includes(':');
|
data.weatherForecast = weatherStr.substring(firstCommaIndex + 1).trim();
|
||||||
const notInfoBox = !line.includes('Info Box');
|
} else {
|
||||||
const notDivider = !line.includes('---');
|
// No clear separation - assume it's all forecast text
|
||||||
const notCodeFence = !line.trim().startsWith('```');
|
data.weatherEmoji = '🌤️'; // Default emoji
|
||||||
|
data.weatherForecast = weatherStr;
|
||||||
|
}
|
||||||
|
|
||||||
// console.log('[RPG Companion] → Checking weather conditions:', {
|
parsedFields.weather = true;
|
||||||
// line: line,
|
}
|
||||||
// hasColon: hasColon,
|
} else {
|
||||||
// notInfoBox: notInfoBox,
|
// Check if it's a legacy weather line (emoji format)
|
||||||
// notDivider: notDivider
|
// Only parse if we haven't already found weather in text format
|
||||||
// });
|
if (!parsedFields.weather) {
|
||||||
|
// Since \p{Emoji} doesn't work reliably, use a simpler approach
|
||||||
|
const hasColon = line.includes(':');
|
||||||
|
const notInfoBox = !line.includes('Info Box');
|
||||||
|
const notDivider = !line.includes('---');
|
||||||
|
const notCodeFence = !line.trim().startsWith('```');
|
||||||
|
|
||||||
if (hasColon && notInfoBox && notDivider && notCodeFence && line.trim().length > 0) {
|
// console.log('[RPG Companion] → Checking weather conditions:', {
|
||||||
// Match format: [Weather Emoji]: [Forecast]
|
// line: line,
|
||||||
// Capture everything before colon as emoji, everything after as forecast
|
// hasColon: hasColon,
|
||||||
// console.log('[RPG Companion] → Testing WEATHER match for:', line);
|
// notInfoBox: notInfoBox,
|
||||||
const weatherMatch = line.match(/^\s*([^:]+):\s*(.+)$/);
|
// notDivider: notDivider
|
||||||
if (weatherMatch) {
|
// });
|
||||||
const potentialEmoji = weatherMatch[1].trim();
|
|
||||||
const forecast = weatherMatch[2].trim();
|
|
||||||
|
|
||||||
// If the first part is short (likely emoji), treat as weather
|
if (hasColon && notInfoBox && notDivider && notCodeFence && line.trim().length > 0) {
|
||||||
if (potentialEmoji.length <= 5) {
|
// Match format: [Weather Emoji]: [Forecast]
|
||||||
data.weatherEmoji = potentialEmoji;
|
// Capture everything before colon as emoji, everything after as forecast
|
||||||
data.weatherForecast = forecast;
|
// console.log('[RPG Companion] → Testing WEATHER match for:', line);
|
||||||
parsedFields.weather = true;
|
const weatherMatch = line.match(/^\s*([^:]+):\s*(.+)$/);
|
||||||
// console.log('[RPG Companion] ✓ Weather parsed:', data.weatherEmoji, data.weatherForecast);
|
if (weatherMatch) {
|
||||||
|
const potentialEmoji = weatherMatch[1].trim();
|
||||||
|
const forecast = weatherMatch[2].trim();
|
||||||
|
|
||||||
|
// If the first part is short (likely emoji), treat as weather
|
||||||
|
if (potentialEmoji.length <= 5) {
|
||||||
|
data.weatherEmoji = potentialEmoji;
|
||||||
|
data.weatherForecast = forecast;
|
||||||
|
parsedFields.weather = true;
|
||||||
|
// console.log('[RPG Companion] ✓ Weather parsed:', data.weatherEmoji, data.weatherForecast);
|
||||||
|
} else {
|
||||||
|
// console.log('[RPG Companion] ✗ First part too long for emoji:', potentialEmoji);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// console.log('[RPG Companion] ✗ First part too long for emoji:', potentialEmoji);
|
// console.log('[RPG Companion] ✗ Weather regex did not match');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// console.log('[RPG Companion] ✗ Weather regex did not match');
|
// console.log('[RPG Companion] → No match for this line');
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// console.log('[RPG Companion] → No match for this line');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// console.log('[RPG Companion] Parsed Info Box data:', {
|
// console.log('[RPG Companion] Parsed Info Box data:', {
|
||||||
// date: data.date,
|
// date: data.date,
|
||||||
// weatherEmoji: data.weatherEmoji,
|
// weatherEmoji: data.weatherEmoji,
|
||||||
// weatherForecast: data.weatherForecast,
|
// weatherForecast: data.weatherForecast,
|
||||||
// temperature: data.temperature,
|
// temperature: data.temperature,
|
||||||
// timeStart: data.timeStart,
|
// timeStart: data.timeStart,
|
||||||
// location: data.location
|
// location: data.location
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get tracker configuration
|
// Get tracker configuration
|
||||||
@@ -363,9 +363,9 @@ export function renderInfoBox() {
|
|||||||
row1Widgets.push(`
|
row1Widgets.push(`
|
||||||
<div class="rpg-dashboard-widget rpg-calendar-widget">
|
<div class="rpg-dashboard-widget rpg-calendar-widget">
|
||||||
${dateLockIconHtml}
|
${dateLockIconHtml}
|
||||||
<div class="rpg-calendar-top rpg-editable" contenteditable="true" data-field="month" data-full-value="${data.month || ''}" title="Click to edit">${monthDisplay}</div>
|
<div class="rpg-calendar-top rpg-editable" contenteditable="true" data-field="month" data-full-value="${data.month || ''}" title="${i18n.getTranslation('infoBox.clickToEdit')}">${monthDisplay}</div>
|
||||||
<div class="rpg-calendar-day" title="Click to edit"><span class="rpg-calendar-day-text rpg-editable" contenteditable="true" data-field="weekday" data-full-value="${data.weekday || ''}">${weekdayDisplay}</span></div>
|
<div class="rpg-calendar-day" title="${i18n.getTranslation('infoBox.clickToEdit')}"><span class="rpg-calendar-day-text rpg-editable" contenteditable="true" data-field="weekday" data-full-value="${data.weekday || ''}">${weekdayDisplay}</span></div>
|
||||||
<div class="rpg-calendar-year rpg-editable" contenteditable="true" data-field="year" data-full-value="${data.year || ''}" title="Click to edit">${yearDisplay}</div>
|
<div class="rpg-calendar-year rpg-editable" contenteditable="true" data-field="year" data-full-value="${data.year || ''}" title="${i18n.getTranslation('infoBox.clickToEdit')}">${yearDisplay}</div>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
@@ -373,14 +373,14 @@ export function renderInfoBox() {
|
|||||||
// Weather widget - show if enabled
|
// Weather widget - show if enabled
|
||||||
if (config?.widgets?.weather?.enabled) {
|
if (config?.widgets?.weather?.enabled) {
|
||||||
const weatherEmoji = data.weatherEmoji || '🌤️';
|
const weatherEmoji = data.weatherEmoji || '🌤️';
|
||||||
const weatherForecast = data.weatherForecast || 'Weather';
|
const weatherForecast = data.weatherForecast || i18n.getTranslation('infoBox.weatherFallback');
|
||||||
const weatherLockIconHtml = getLockIconHtml('infoBox', 'weather');
|
const weatherLockIconHtml = getLockIconHtml('infoBox', 'weather');
|
||||||
|
|
||||||
row1Widgets.push(`
|
row1Widgets.push(`
|
||||||
<div class="rpg-dashboard-widget rpg-weather-widget">
|
<div class="rpg-dashboard-widget rpg-weather-widget">
|
||||||
${weatherLockIconHtml}
|
${weatherLockIconHtml}
|
||||||
<div class="rpg-weather-icon rpg-editable" contenteditable="true" data-field="weatherEmoji" title="Click to edit emoji">${weatherEmoji}</div>
|
<div class="rpg-weather-icon rpg-editable" contenteditable="true" data-field="weatherEmoji" title="${i18n.getTranslation('userStats.clickToEditEmoji')}">${weatherEmoji}</div>
|
||||||
<div class="rpg-weather-forecast rpg-editable" contenteditable="true" data-field="weatherForecast" title="Click to edit">${weatherForecast}</div>
|
<div class="rpg-weather-forecast rpg-editable" contenteditable="true" data-field="weatherForecast" title="${i18n.getTranslation('infoBox.clickToEdit')}">${weatherForecast}</div>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
@@ -399,12 +399,12 @@ export function renderInfoBox() {
|
|||||||
|
|
||||||
if (preferredUnit === 'F' && isCelsius) {
|
if (preferredUnit === 'F' && isCelsius) {
|
||||||
// Convert C to F
|
// Convert C to F
|
||||||
const fahrenheit = Math.round((tempValue * 9/5) + 32);
|
const fahrenheit = Math.round((tempValue * 9 / 5) + 32);
|
||||||
tempDisplay = `${fahrenheit}°F`;
|
tempDisplay = `${fahrenheit}°F`;
|
||||||
tempValue = fahrenheit;
|
tempValue = fahrenheit;
|
||||||
} else if (preferredUnit === 'C' && isFahrenheit) {
|
} else if (preferredUnit === 'C' && isFahrenheit) {
|
||||||
// Convert F to C
|
// Convert F to C
|
||||||
const celsius = Math.round((tempValue - 32) * 5/9);
|
const celsius = Math.round((tempValue - 32) * 5 / 9);
|
||||||
tempDisplay = `${celsius}°C`;
|
tempDisplay = `${celsius}°C`;
|
||||||
tempValue = celsius;
|
tempValue = celsius;
|
||||||
}
|
}
|
||||||
@@ -415,7 +415,7 @@ export function renderInfoBox() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate thermometer display (convert to Celsius for consistent thresholds)
|
// Calculate thermometer display (convert to Celsius for consistent thresholds)
|
||||||
const tempInCelsius = preferredUnit === 'F' ? Math.round((tempValue - 32) * 5/9) : tempValue;
|
const tempInCelsius = preferredUnit === 'F' ? Math.round((tempValue - 32) * 5 / 9) : tempValue;
|
||||||
const tempPercent = Math.min(100, Math.max(0, ((tempInCelsius + 20) / 60) * 100));
|
const tempPercent = Math.min(100, Math.max(0, ((tempInCelsius + 20) / 60) * 100));
|
||||||
const tempColor = tempInCelsius < 10 ? '#4a90e2' : tempInCelsius < 25 ? '#67c23a' : '#e94560';
|
const tempColor = tempInCelsius < 10 ? '#4a90e2' : tempInCelsius < 25 ? '#67c23a' : '#e94560';
|
||||||
const tempLockIconHtml = getLockIconHtml('infoBox', 'temperature');
|
const tempLockIconHtml = getLockIconHtml('infoBox', 'temperature');
|
||||||
@@ -429,7 +429,7 @@ export function renderInfoBox() {
|
|||||||
<div class="rpg-thermometer-fill" style="height: ${tempPercent}%; background: ${tempColor}"></div>
|
<div class="rpg-thermometer-fill" style="height: ${tempPercent}%; background: ${tempColor}"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rpg-temp-value rpg-editable" contenteditable="true" data-field="temperature" title="Click to edit">${tempDisplay}</div>
|
<div class="rpg-temp-value rpg-editable" contenteditable="true" data-field="temperature" title="${i18n.getTranslation('infoBox.clickToEdit')}">${tempDisplay}</div>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
@@ -464,9 +464,9 @@ export function renderInfoBox() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rpg-time-range">
|
<div class="rpg-time-range">
|
||||||
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeStart" title="Click to edit start time">${timeStartDisplay}</div>
|
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeStart" title="${i18n.getTranslation('infoBox.clickToEdit')}">${timeStartDisplay}</div>
|
||||||
<span class="rpg-time-separator">→</span>
|
<span class="rpg-time-separator">→</span>
|
||||||
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeEnd" title="Click to edit end time">${timeEndDisplay}</div>
|
<div class="rpg-time-value rpg-editable" contenteditable="true" data-field="timeEnd" title="${i18n.getTranslation('infoBox.clickToEdit')}">${timeEndDisplay}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
@@ -481,7 +481,7 @@ export function renderInfoBox() {
|
|||||||
|
|
||||||
// Row 2: Location widget (full width) - show if enabled
|
// Row 2: Location widget (full width) - show if enabled
|
||||||
if (config?.widgets?.location?.enabled) {
|
if (config?.widgets?.location?.enabled) {
|
||||||
const locationDisplay = data.location || 'Location';
|
const locationDisplay = data.location || i18n.getTranslation('infoBox.locationFallback');
|
||||||
const locationLockIconHtml = getLockIconHtml('infoBox', 'location');
|
const locationLockIconHtml = getLockIconHtml('infoBox', 'location');
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
@@ -491,7 +491,7 @@ export function renderInfoBox() {
|
|||||||
<div class="rpg-map-bg">
|
<div class="rpg-map-bg">
|
||||||
<div class="rpg-map-marker">📍</div>
|
<div class="rpg-map-marker">📍</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rpg-location-text rpg-editable" contenteditable="true" data-field="location" title="Click to edit">${locationDisplay}</div>
|
<div class="rpg-location-text rpg-editable" contenteditable="true" data-field="location" title="${i18n.getTranslation('infoBox.clickToEdit')}">${locationDisplay}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -550,7 +550,7 @@ export function renderInfoBox() {
|
|||||||
html += `
|
html += `
|
||||||
<div class="rpg-notebook-line">
|
<div class="rpg-notebook-line">
|
||||||
<span class="rpg-bullet">•</span>
|
<span class="rpg-bullet">•</span>
|
||||||
<span class="rpg-event-text rpg-editable" contenteditable="true" data-field="event${i + 1}" title="Click to edit">${validEvents[i]}</span>
|
<span class="rpg-event-text rpg-editable" contenteditable="true" data-field="event${i + 1}" title="${i18n.getTranslation('infoBox.clickToEdit')}">${validEvents[i]}</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -591,7 +591,7 @@ export function renderInfoBox() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add event handlers for editable Info Box fields
|
// Add event handlers for editable Info Box fields
|
||||||
$infoBoxContainer.find('.rpg-editable').on('blur', function() {
|
$infoBoxContainer.find('.rpg-editable').on('blur', function () {
|
||||||
const $this = $(this);
|
const $this = $(this);
|
||||||
const field = $this.data('field');
|
const field = $this.data('field');
|
||||||
const value = $this.text().trim();
|
const value = $this.text().trim();
|
||||||
@@ -624,12 +624,12 @@ export function renderInfoBox() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Update location size on input as well (real-time)
|
// Update location size on input as well (real-time)
|
||||||
$infoBoxContainer.find('[data-field="location"]').on('input', function() {
|
$infoBoxContainer.find('[data-field="location"]').on('input', function () {
|
||||||
updateLocationTextSize($(this));
|
updateLocationTextSize($(this));
|
||||||
});
|
});
|
||||||
|
|
||||||
// For date fields, show full value on focus
|
// For date fields, show full value on focus
|
||||||
$infoBoxContainer.find('[data-field="month"], [data-field="weekday"], [data-field="year"]').on('focus', function() {
|
$infoBoxContainer.find('[data-field="month"], [data-field="weekday"], [data-field="year"]').on('focus', function () {
|
||||||
const fullValue = $(this).data('full-value');
|
const fullValue = $(this).data('full-value');
|
||||||
if (fullValue) {
|
if (fullValue) {
|
||||||
$(this).text(fullValue);
|
$(this).text(fullValue);
|
||||||
@@ -637,7 +637,7 @@ export function renderInfoBox() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add event handler for lock icons (support both click and touch)
|
// Add event handler for lock icons (support both click and touch)
|
||||||
$infoBoxContainer.find('.rpg-section-lock-icon').on('click touchend', function(e) {
|
$infoBoxContainer.find('.rpg-section-lock-icon').on('click touchend', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const $lockIcon = $(this);
|
const $lockIcon = $(this);
|
||||||
@@ -652,7 +652,7 @@ export function renderInfoBox() {
|
|||||||
|
|
||||||
// Update icon
|
// Update icon
|
||||||
$lockIcon.text(newLockState ? '🔒' : '🔓');
|
$lockIcon.text(newLockState ? '🔒' : '🔓');
|
||||||
$lockIcon.attr('title', newLockState ? 'Locked - AI cannot change this' : 'Unlocked - AI can change this');
|
$lockIcon.attr('title', newLockState ? i18n.getTranslation('infoBox.locked') : i18n.getTranslation('infoBox.unlocked'));
|
||||||
$lockIcon.toggleClass('locked', newLockState);
|
$lockIcon.toggleClass('locked', newLockState);
|
||||||
|
|
||||||
// Save settings to persist lock state
|
// Save settings to persist lock state
|
||||||
|
|||||||
+157
-156
@@ -14,6 +14,7 @@ import {
|
|||||||
FALLBACK_AVATAR_DATA_URI,
|
FALLBACK_AVATAR_DATA_URI,
|
||||||
addDebugLog
|
addDebugLog
|
||||||
} from '../../core/state.js';
|
} from '../../core/state.js';
|
||||||
|
import { i18n } from '../../core/i18n.js';
|
||||||
import { saveChatData, saveSettings } from '../../core/persistence.js';
|
import { saveChatData, saveSettings } from '../../core/persistence.js';
|
||||||
import { getSafeThumbnailUrl } from '../../utils/avatars.js';
|
import { getSafeThumbnailUrl } from '../../utils/avatars.js';
|
||||||
import { isItemLocked, setItemLock } from '../generation/lockManager.js';
|
import { isItemLocked, setItemLock } from '../generation/lockManager.js';
|
||||||
@@ -30,7 +31,7 @@ function getLockIconHtml(tracker, path) {
|
|||||||
|
|
||||||
const isLocked = isItemLocked(tracker, path);
|
const isLocked = isItemLocked(tracker, path);
|
||||||
const lockIcon = isLocked ? '🔒' : '🔓';
|
const lockIcon = isLocked ? '🔒' : '🔓';
|
||||||
const lockTitle = isLocked ? 'Locked' : 'Unlocked';
|
const lockTitle = isLocked ? i18n.getTranslation('thoughts.locked') : i18n.getTranslation('thoughts.unlocked');
|
||||||
const lockedClass = isLocked ? ' locked' : '';
|
const lockedClass = isLocked ? ' locked' : '';
|
||||||
return `<span class="rpg-section-lock-icon${lockedClass}" data-tracker="${tracker}" data-path="${path}" title="${lockTitle}">${lockIcon}</span>`;
|
return `<span class="rpg-section-lock-icon${lockedClass}" data-tracker="${tracker}" data-path="${path}" title="${lockTitle}">${lockIcon}</span>`;
|
||||||
}
|
}
|
||||||
@@ -300,88 +301,88 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
debugLog('[RPG Thoughts] Split into lines count:', lines.length);
|
debugLog('[RPG Thoughts] Split into lines count:', lines.length);
|
||||||
debugLog('[RPG Thoughts] Lines:', lines);
|
debugLog('[RPG Thoughts] Lines:', lines);
|
||||||
|
|
||||||
// Parse new multi-line format:
|
// Parse new multi-line format:
|
||||||
// - [Name]
|
// - [Name]
|
||||||
// Details: [Emoji] | [Field1] | [Field2] | ...
|
// Details: [Emoji] | [Field1] | [Field2] | ...
|
||||||
// Relationship: [Relationship]
|
// Relationship: [Relationship]
|
||||||
// Stats: Stat1: X% | Stat2: X% | ...
|
// Stats: Stat1: X% | Stat2: X% | ...
|
||||||
// Thoughts: [Description]
|
// Thoughts: [Description]
|
||||||
let lineNumber = 0;
|
let lineNumber = 0;
|
||||||
let currentCharacter = null;
|
let currentCharacter = null;
|
||||||
|
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
lineNumber++;
|
lineNumber++;
|
||||||
|
|
||||||
// Skip empty lines, headers, dividers, and code fences
|
// Skip empty lines, headers, dividers, and code fences
|
||||||
if (!line.trim() ||
|
if (!line.trim() ||
|
||||||
line.includes('Present Characters') ||
|
line.includes('Present Characters') ||
|
||||||
line.includes('---') ||
|
line.includes('---') ||
|
||||||
line.trim().startsWith('```') ||
|
line.trim().startsWith('```') ||
|
||||||
line.trim() === '- …' ||
|
line.trim() === '- …' ||
|
||||||
line.includes('(Repeat the format')) {
|
line.includes('(Repeat the format')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
debugLog(`[RPG Thoughts] Processing line ${lineNumber}:`, line);
|
|
||||||
|
|
||||||
// Check if this is a character name line (starts with "- ")
|
|
||||||
if (line.trim().startsWith('- ')) {
|
|
||||||
const name = line.trim().substring(2).trim();
|
|
||||||
|
|
||||||
if (name && name.toLowerCase() !== 'unavailable') {
|
|
||||||
currentCharacter = { name };
|
|
||||||
presentCharacters.push(currentCharacter);
|
|
||||||
debugLog(`[RPG Thoughts] ✓ Started new character: ${name}`);
|
|
||||||
} else {
|
|
||||||
currentCharacter = null;
|
|
||||||
debugLog(`[RPG Thoughts] ✗ Rejected character - name: "${name}" (unavailable or empty)`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check if this is a Details line
|
|
||||||
else if (line.trim().startsWith('Details:') && currentCharacter) {
|
|
||||||
const detailsContent = line.substring(line.indexOf(':') + 1).trim();
|
|
||||||
const parts = detailsContent.split('|').map(p => p.trim());
|
|
||||||
|
|
||||||
// First part is the emoji
|
|
||||||
if (parts.length > 0) {
|
|
||||||
currentCharacter.emoji = parts[0];
|
|
||||||
debugLog(`[RPG Thoughts] Parsed emoji: ${parts[0]}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remaining parts are custom fields
|
debugLog(`[RPG Thoughts] Processing line ${lineNumber}:`, line);
|
||||||
for (let i = 0; i < enabledFields.length && i + 1 < parts.length; i++) {
|
|
||||||
const fieldName = enabledFields[i].name;
|
|
||||||
currentCharacter[fieldName] = parts[i + 1];
|
|
||||||
debugLog(`[RPG Thoughts] Parsed field ${fieldName}: ${parts[i + 1]}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check if this is a Relationship line
|
|
||||||
else if (line.trim().startsWith('Relationship:') && currentCharacter) {
|
|
||||||
const relationship = line.substring(line.indexOf(':') + 1).trim();
|
|
||||||
currentCharacter.Relationship = relationship;
|
|
||||||
debugLog(`[RPG Thoughts] Parsed relationship: ${relationship}`);
|
|
||||||
}
|
|
||||||
// Check if this is a Stats line
|
|
||||||
else if (line.trim().startsWith('Stats:') && currentCharacter && enabledCharStats.length > 0) {
|
|
||||||
const statsContent = line.substring(line.indexOf(':') + 1).trim();
|
|
||||||
const statParts = statsContent.split('|').map(p => p.trim());
|
|
||||||
|
|
||||||
for (const statPart of statParts) {
|
// Check if this is a character name line (starts with "- ")
|
||||||
const statMatch = statPart.match(/^(.+?):\s*(\d+)%$/);
|
if (line.trim().startsWith('- ')) {
|
||||||
if (statMatch) {
|
const name = line.trim().substring(2).trim();
|
||||||
const statName = statMatch[1].trim();
|
|
||||||
const statValue = parseInt(statMatch[2]);
|
if (name && name.toLowerCase() !== 'unavailable') {
|
||||||
currentCharacter[statName] = statValue;
|
currentCharacter = { name };
|
||||||
debugLog(`[RPG Thoughts] Parsed stat: ${statName} = ${statValue}%`);
|
presentCharacters.push(currentCharacter);
|
||||||
|
debugLog(`[RPG Thoughts] ✓ Started new character: ${name}`);
|
||||||
|
} else {
|
||||||
|
currentCharacter = null;
|
||||||
|
debugLog(`[RPG Thoughts] ✗ Rejected character - name: "${name}" (unavailable or empty)`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Check if this is a Details line
|
||||||
|
else if (line.trim().startsWith('Details:') && currentCharacter) {
|
||||||
|
const detailsContent = line.substring(line.indexOf(':') + 1).trim();
|
||||||
|
const parts = detailsContent.split('|').map(p => p.trim());
|
||||||
|
|
||||||
|
// First part is the emoji
|
||||||
|
if (parts.length > 0) {
|
||||||
|
currentCharacter.emoji = parts[0];
|
||||||
|
debugLog(`[RPG Thoughts] Parsed emoji: ${parts[0]}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remaining parts are custom fields
|
||||||
|
for (let i = 0; i < enabledFields.length && i + 1 < parts.length; i++) {
|
||||||
|
const fieldName = enabledFields[i].name;
|
||||||
|
currentCharacter[fieldName] = parts[i + 1];
|
||||||
|
debugLog(`[RPG Thoughts] Parsed field ${fieldName}: ${parts[i + 1]}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if this is a Relationship line
|
||||||
|
else if (line.trim().startsWith('Relationship:') && currentCharacter) {
|
||||||
|
const relationship = line.substring(line.indexOf(':') + 1).trim();
|
||||||
|
currentCharacter.Relationship = relationship;
|
||||||
|
debugLog(`[RPG Thoughts] Parsed relationship: ${relationship}`);
|
||||||
|
}
|
||||||
|
// Check if this is a Stats line
|
||||||
|
else if (line.trim().startsWith('Stats:') && currentCharacter && enabledCharStats.length > 0) {
|
||||||
|
const statsContent = line.substring(line.indexOf(':') + 1).trim();
|
||||||
|
const statParts = statsContent.split('|').map(p => p.trim());
|
||||||
|
|
||||||
|
for (const statPart of statParts) {
|
||||||
|
const statMatch = statPart.match(/^(.+?):\s*(\d+)%$/);
|
||||||
|
if (statMatch) {
|
||||||
|
const statName = statMatch[1].trim();
|
||||||
|
const statValue = parseInt(statMatch[2]);
|
||||||
|
currentCharacter[statName] = statValue;
|
||||||
|
debugLog(`[RPG Thoughts] Parsed stat: ${statName} = ${statValue}%`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if this is a Thoughts line (handled separately for thought bubbles)
|
||||||
|
else if (line.trim().match(/^[A-Z][a-z]+:/) && currentCharacter) {
|
||||||
|
// This could be Thoughts, Feelings, etc. - skip for now, handled in thought bubble rendering
|
||||||
|
debugLog(`[RPG Thoughts] Skipping thoughts/feelings line (handled in bubble rendering)`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Check if this is a Thoughts line (handled separately for thought bubbles)
|
|
||||||
else if (line.trim().match(/^[A-Z][a-z]+:/) && currentCharacter) {
|
|
||||||
// This could be Thoughts, Feelings, etc. - skip for now, handled in thought bubble rendering
|
|
||||||
debugLog(`[RPG Thoughts] Skipping thoughts/feelings line (handled in bubble rendering)`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // End of text format parsing
|
} // End of text format parsing
|
||||||
|
|
||||||
// Get relationship emojis from config (with fallback defaults)
|
// Get relationship emojis from config (with fallback defaults)
|
||||||
@@ -502,14 +503,14 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
html += `
|
html += `
|
||||||
<div class="rpg-character-card" data-character-name="${char.name}">
|
<div class="rpg-character-card" data-character-name="${char.name}">
|
||||||
<div class="rpg-character-header-row">
|
<div class="rpg-character-header-row">
|
||||||
<div class="rpg-character-avatar rpg-avatar-upload" data-character="${char.name}" title="Click to upload avatar">
|
<div class="rpg-character-avatar rpg-avatar-upload" data-character="${char.name}" title="${i18n.getTranslation('thoughts.clickToUpload')}">
|
||||||
<img src="${characterPortrait}" alt="${char.name}" onerror="this.style.opacity='0.5';this.onerror=null;" />
|
<img src="${characterPortrait}" alt="${char.name}" onerror="this.style.opacity='0.5';this.onerror=null;" />
|
||||||
${hasRelationshipEnabled ? `<div class="rpg-relationship-badge rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${relationshipFieldName}" title="Click to edit (use emoji: ⚔️ ⚖️ ⭐ ❤️)">${relationshipBadge}</div>` : ''}
|
${hasRelationshipEnabled ? `<div class="rpg-relationship-badge rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${relationshipFieldName}" title="${i18n.getTranslation('thoughts.clickToEdit')} (emoji: ⚔️ ⚖️ ⭐ ❤️)">${relationshipBadge}</div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
<div class="rpg-character-header">
|
<div class="rpg-character-header">
|
||||||
<span class="rpg-character-emoji rpg-editable" contenteditable="true" data-character="${char.name}" data-field="emoji" title="Click to edit emoji">${char.emoji}</span>
|
<span class="rpg-character-emoji rpg-editable" contenteditable="true" data-character="${char.name}" data-field="emoji" title="${i18n.getTranslation('thoughts.clickToEdit')}">${char.emoji}</span>
|
||||||
<span class="rpg-character-name rpg-editable" contenteditable="true" data-character="${char.name}" data-field="name" title="Click to edit name">${char.name}</span>
|
<span class="rpg-character-name rpg-editable" contenteditable="true" data-character="${char.name}" data-field="name" title="${i18n.getTranslation('thoughts.clickToEdit')}">${char.name}</span>
|
||||||
<button class="rpg-character-remove" data-character="${char.name}" title="Remove character">×</button>
|
<button class="rpg-character-remove" data-character="${char.name}" title="${i18n.getTranslation('thoughts.removeCharacter')}">×</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rpg-character-content">
|
<div class="rpg-character-content">
|
||||||
@@ -532,12 +533,12 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
html += `
|
html += `
|
||||||
<div class="rpg-character-field rpg-character-${fieldId}" style="position: relative;">
|
<div class="rpg-character-field rpg-character-${fieldId}" style="position: relative;">
|
||||||
${lockIconHtml}
|
${lockIconHtml}
|
||||||
<span class="rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="Click to edit ${field.name}" ${placeholder}>${fieldValue}</span>
|
<span class="rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="${i18n.getTranslation('thoughts.clickToEdit')}" ${placeholder}>${fieldValue}</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
html += `
|
html += `
|
||||||
<div class="rpg-character-field rpg-character-${fieldId} rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="Click to edit ${field.name}" ${placeholder}>${fieldValue}</div>
|
<div class="rpg-character-field rpg-character-${fieldId} rpg-editable${emptyClass}" contenteditable="true" data-character="${char.name}" data-field="${field.name}" title="${i18n.getTranslation('thoughts.clickToEdit')}" ${placeholder}>${fieldValue}</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,7 +564,7 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
);
|
);
|
||||||
html += `
|
html += `
|
||||||
<div class="rpg-character-stat">
|
<div class="rpg-character-stat">
|
||||||
<span class="rpg-stat-name">${stat.name}: </span><span class="rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${stat.name}" style="color: ${statColor}" title="Click to edit ${stat.name}">${statValue}%</span>
|
<span class="rpg-stat-name">${stat.name}: </span><span class="rpg-editable" contenteditable="true" data-character="${char.name}" data-field="${stat.name}" style="color: ${statColor}" title="${i18n.getTranslation('thoughts.clickToEdit')}">${statValue}%</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -589,8 +590,8 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
// Add "Add Character" button if data exists (inside rpg-thoughts-content)
|
// Add "Add Character" button if data exists (inside rpg-thoughts-content)
|
||||||
if (presentCharacters.length > 0) {
|
if (presentCharacters.length > 0) {
|
||||||
html += `
|
html += `
|
||||||
<button class="rpg-add-character-btn" title="Add a new character">
|
<button class="rpg-add-character-btn" title="${i18n.getTranslation('thoughts.addCharacter')}">
|
||||||
<i class="fa-solid fa-plus"></i> Add Character
|
<i class="fa-solid fa-plus"></i> ${i18n.getTranslation('thoughts.addCharacter')}
|
||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -604,7 +605,7 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
debugLog('[RPG Thoughts] =======================================================');
|
debugLog('[RPG Thoughts] =======================================================');
|
||||||
|
|
||||||
// Add event handlers for editable character fields
|
// Add event handlers for editable character fields
|
||||||
$thoughtsContainer.find('.rpg-editable').on('blur', function() {
|
$thoughtsContainer.find('.rpg-editable').on('blur', function () {
|
||||||
const character = $(this).data('character');
|
const character = $(this).data('character');
|
||||||
const field = $(this).data('field');
|
const field = $(this).data('field');
|
||||||
const value = $(this).text().trim();
|
const value = $(this).text().trim();
|
||||||
@@ -613,12 +614,12 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Prevent click events on editable elements from bubbling to avatar upload handler
|
// Prevent click events on editable elements from bubbling to avatar upload handler
|
||||||
$thoughtsContainer.find('.rpg-editable').on('click mousedown', function(e) {
|
$thoughtsContainer.find('.rpg-editable').on('click mousedown', function (e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add event listener for section lock icon clicks (support both click and touch)
|
// Add event listener for section lock icon clicks (support both click and touch)
|
||||||
$thoughtsContainer.find('.rpg-section-lock-icon').on('click touchend', function(e) {
|
$thoughtsContainer.find('.rpg-section-lock-icon').on('click touchend', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const $icon = $(this);
|
const $icon = $(this);
|
||||||
@@ -643,7 +644,7 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add event listener for character remove button
|
// Add event listener for character remove button
|
||||||
$thoughtsContainer.find('.rpg-character-remove').on('click', function(e) {
|
$thoughtsContainer.find('.rpg-character-remove').on('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
@@ -652,7 +653,7 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add event listener for avatar upload clicks
|
// Add event listener for avatar upload clicks
|
||||||
$thoughtsContainer.find('.rpg-avatar-upload').on('click', function(e) {
|
$thoughtsContainer.find('.rpg-avatar-upload').on('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
@@ -661,13 +662,13 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
// Create hidden file input
|
// Create hidden file input
|
||||||
const fileInput = $('<input type="file" accept="image/*" style="display: none;">');
|
const fileInput = $('<input type="file" accept="image/*" style="display: none;">');
|
||||||
|
|
||||||
fileInput.on('change', function() {
|
fileInput.on('change', function () {
|
||||||
const file = this.files[0];
|
const file = this.files[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
// Read file as data URL
|
// Read file as data URL
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = function(e) {
|
reader.onload = function (e) {
|
||||||
const imageUrl = e.target.result;
|
const imageUrl = e.target.result;
|
||||||
|
|
||||||
// Store in npcAvatars
|
// Store in npcAvatars
|
||||||
@@ -694,20 +695,20 @@ export function renderThoughts({ preserveScroll = false } = {}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add event listener for "Add Character" button (support both click and touch for mobile)
|
// Add event listener for "Add Character" button (support both click and touch for mobile)
|
||||||
$thoughtsContainer.find('.rpg-add-character-btn').on('click touchend', function(e) {
|
$thoughtsContainer.find('.rpg-add-character-btn').on('click touchend', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
addNewCharacter();
|
addNewCharacter();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle empty field focus - remove placeholder styling on focus
|
// Handle empty field focus - remove placeholder styling on focus
|
||||||
$thoughtsContainer.find('.rpg-editable.rpg-empty-field').on('focus', function() {
|
$thoughtsContainer.find('.rpg-editable.rpg-empty-field').on('focus', function () {
|
||||||
$(this).removeClass('rpg-empty-field');
|
$(this).removeClass('rpg-empty-field');
|
||||||
$(this).removeAttr('data-placeholder');
|
$(this).removeAttr('data-placeholder');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Restore placeholder if field becomes empty on blur (after the main blur handler)
|
// Restore placeholder if field becomes empty on blur (after the main blur handler)
|
||||||
$thoughtsContainer.find('.rpg-editable').on('blur', function() {
|
$thoughtsContainer.find('.rpg-editable').on('blur', function () {
|
||||||
const $this = $(this);
|
const $this = $(this);
|
||||||
if (!$this.text().trim()) {
|
if (!$this.text().trim()) {
|
||||||
const field = $this.data('field');
|
const field = $this.data('field');
|
||||||
@@ -1494,59 +1495,59 @@ export function updateChatThoughts() {
|
|||||||
if (thoughtsArray.length === 0) {
|
if (thoughtsArray.length === 0) {
|
||||||
const lines = lastGeneratedData.characterThoughts.split('\n');
|
const lines = lastGeneratedData.characterThoughts.split('\n');
|
||||||
|
|
||||||
// console.log('[RPG Companion] Parsing thoughts from lines:', lines);
|
// console.log('[RPG Companion] Parsing thoughts from lines:', lines);
|
||||||
|
|
||||||
// Parse new format to build character map and thoughts
|
// Parse new format to build character map and thoughts
|
||||||
let currentCharName = null;
|
let currentCharName = null;
|
||||||
let currentCharEmoji = null;
|
let currentCharEmoji = null;
|
||||||
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
const line = lines[i].trim();
|
const line = lines[i].trim();
|
||||||
|
|
||||||
if (!line ||
|
if (!line ||
|
||||||
line.includes('Present Characters') ||
|
line.includes('Present Characters') ||
|
||||||
line.includes('---') ||
|
line.includes('---') ||
|
||||||
line.startsWith('```') ||
|
line.startsWith('```') ||
|
||||||
line.trim() === '- …' ||
|
line.trim() === '- …' ||
|
||||||
line.includes('(Repeat the format')) {
|
line.includes('(Repeat the format')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is a character name line (starts with "- ")
|
// Check if this is a character name line (starts with "- ")
|
||||||
if (line.startsWith('- ')) {
|
if (line.startsWith('- ')) {
|
||||||
const name = line.substring(2).trim();
|
const name = line.substring(2).trim();
|
||||||
if (name && name.toLowerCase() !== 'unavailable') {
|
if (name && name.toLowerCase() !== 'unavailable') {
|
||||||
currentCharName = name;
|
currentCharName = name;
|
||||||
currentCharEmoji = null; // Reset emoji for new character
|
currentCharEmoji = null; // Reset emoji for new character
|
||||||
} else {
|
} else {
|
||||||
currentCharName = null;
|
currentCharName = null;
|
||||||
currentCharEmoji = null;
|
currentCharEmoji = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if this is a Details line (contains the emoji)
|
||||||
|
else if (line.startsWith('Details:') && currentCharName) {
|
||||||
|
const detailsContent = line.substring(line.indexOf(':') + 1).trim();
|
||||||
|
const parts = detailsContent.split('|').map(p => p.trim());
|
||||||
|
|
||||||
|
// First part is the emoji
|
||||||
|
if (parts.length > 0) {
|
||||||
|
currentCharEmoji = parts[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if this is a Thoughts line
|
||||||
|
else if (line.startsWith(thoughtsLabel + ':') && currentCharName && currentCharEmoji) {
|
||||||
|
const thoughtContent = line.substring(thoughtsLabel.length + 1).trim();
|
||||||
|
|
||||||
|
// The thought content is just the text (no emoji prefix in new format)
|
||||||
|
if (thoughtContent) {
|
||||||
|
thoughtsArray.push({
|
||||||
|
name: currentCharName.toLowerCase(),
|
||||||
|
emoji: currentCharEmoji,
|
||||||
|
thought: thoughtContent
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check if this is a Details line (contains the emoji)
|
|
||||||
else if (line.startsWith('Details:') && currentCharName) {
|
|
||||||
const detailsContent = line.substring(line.indexOf(':') + 1).trim();
|
|
||||||
const parts = detailsContent.split('|').map(p => p.trim());
|
|
||||||
|
|
||||||
// First part is the emoji
|
|
||||||
if (parts.length > 0) {
|
|
||||||
currentCharEmoji = parts[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check if this is a Thoughts line
|
|
||||||
else if (line.startsWith(thoughtsLabel + ':') && currentCharName && currentCharEmoji) {
|
|
||||||
const thoughtContent = line.substring(thoughtsLabel.length + 1).trim();
|
|
||||||
|
|
||||||
// The thought content is just the text (no emoji prefix in new format)
|
|
||||||
if (thoughtContent) {
|
|
||||||
thoughtsArray.push({
|
|
||||||
name: currentCharName.toLowerCase(),
|
|
||||||
emoji: currentCharEmoji,
|
|
||||||
thought: thoughtContent
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // End of text format parsing for thoughts bubbles
|
} // End of text format parsing for thoughts bubbles
|
||||||
|
|
||||||
debugLog('[RPG Thoughts] Parsed thoughts:', thoughtsArray);
|
debugLog('[RPG Thoughts] Parsed thoughts:', thoughtsArray);
|
||||||
@@ -1628,7 +1629,7 @@ function attachDragHandlersToIcon($icon) {
|
|||||||
$icon.off('.thoughtIconDrag');
|
$icon.off('.thoughtIconDrag');
|
||||||
|
|
||||||
// Test: add a simple click handler to verify events work
|
// Test: add a simple click handler to verify events work
|
||||||
$icon.on('click.thoughtIconDrag', function(e) {
|
$icon.on('click.thoughtIconDrag', function (e) {
|
||||||
// Check global flag set immediately after drag completes
|
// Check global flag set immediately after drag completes
|
||||||
if (justFinishedDragging) {
|
if (justFinishedDragging) {
|
||||||
// console.log('[Thought Icon] CLICK blocked - just finished dragging');
|
// console.log('[Thought Icon] CLICK blocked - just finished dragging');
|
||||||
@@ -1641,7 +1642,7 @@ function attachDragHandlersToIcon($icon) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Touch drag support - mobile only
|
// Touch drag support - mobile only
|
||||||
$icon.on('touchstart.thoughtIconDrag', function(e) {
|
$icon.on('touchstart.thoughtIconDrag', function (e) {
|
||||||
if (window.innerWidth > 1000) return;
|
if (window.innerWidth > 1000) return;
|
||||||
|
|
||||||
// console.log('[Thought Icon] touchstart');
|
// console.log('[Thought Icon] touchstart');
|
||||||
@@ -1658,7 +1659,7 @@ function attachDragHandlersToIcon($icon) {
|
|||||||
isDragging = false;
|
isDragging = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
$icon.on('touchmove.thoughtIconDrag', function(e) {
|
$icon.on('touchmove.thoughtIconDrag', function (e) {
|
||||||
if (window.innerWidth > 1000) return;
|
if (window.innerWidth > 1000) return;
|
||||||
|
|
||||||
if (!touchMoved) {
|
if (!touchMoved) {
|
||||||
@@ -1701,7 +1702,7 @@ function attachDragHandlersToIcon($icon) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$icon.on('touchend.thoughtIconDrag', function(e) {
|
$icon.on('touchend.thoughtIconDrag', function (e) {
|
||||||
// console.log('[Thought Icon] touchend - isDragging:', isDragging, 'touchMoved:', touchMoved);
|
// console.log('[Thought Icon] touchend - isDragging:', isDragging, 'touchMoved:', touchMoved);
|
||||||
|
|
||||||
if (isDragging) {
|
if (isDragging) {
|
||||||
@@ -1756,7 +1757,7 @@ function attachDragHandlersToIcon($icon) {
|
|||||||
// Mouse drag support - mobile only
|
// Mouse drag support - mobile only
|
||||||
let mouseDown = false;
|
let mouseDown = false;
|
||||||
|
|
||||||
$icon.on('mousedown.thoughtIconDrag', function(e) {
|
$icon.on('mousedown.thoughtIconDrag', function (e) {
|
||||||
if (window.innerWidth > 1000) return;
|
if (window.innerWidth > 1000) return;
|
||||||
|
|
||||||
// console.log('[Thought Icon] mousedown');
|
// console.log('[Thought Icon] mousedown');
|
||||||
@@ -1775,7 +1776,7 @@ function attachDragHandlersToIcon($icon) {
|
|||||||
isDragging = false;
|
isDragging = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('mousemove.thoughtIconDrag', function(e) {
|
$(document).on('mousemove.thoughtIconDrag', function (e) {
|
||||||
if (!mouseDown || window.innerWidth > 1000) return;
|
if (!mouseDown || window.innerWidth > 1000) return;
|
||||||
|
|
||||||
if (!touchMoved) {
|
if (!touchMoved) {
|
||||||
@@ -1819,7 +1820,7 @@ function attachDragHandlersToIcon($icon) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('mouseup.thoughtIconDrag', function(e) {
|
$(document).on('mouseup.thoughtIconDrag', function (e) {
|
||||||
if (!mouseDown) return;
|
if (!mouseDown) return;
|
||||||
|
|
||||||
// console.log('[Thought Icon] mouseup - isDragging:', isDragging, 'touchMoved:', touchMoved);
|
// console.log('[Thought Icon] mouseup - isDragging:', isDragging, 'touchMoved:', touchMoved);
|
||||||
@@ -2222,7 +2223,7 @@ export function createThoughtPanel($message, thoughtsArray) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Close button functionality - support both click and touch
|
// Close button functionality - support both click and touch
|
||||||
$thoughtPanel.find('.rpg-thought-close').on('click touchend', function(e) {
|
$thoughtPanel.find('.rpg-thought-close').on('click touchend', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
@@ -2230,7 +2231,7 @@ export function createThoughtPanel($message, thoughtsArray) {
|
|||||||
|
|
||||||
if (isMobileView) {
|
if (isMobileView) {
|
||||||
// Mobile: hide panel and show icon
|
// Mobile: hide panel and show icon
|
||||||
$thoughtPanel.fadeOut(200, function() {
|
$thoughtPanel.fadeOut(200, function () {
|
||||||
// Make sure icon is visible and clean state when panel closes (use selector, not variable)
|
// Make sure icon is visible and clean state when panel closes (use selector, not variable)
|
||||||
const $icon = $('#rpg-thought-icon');
|
const $icon = $('#rpg-thought-icon');
|
||||||
$icon.removeClass('rpg-hidden dragging');
|
$icon.removeClass('rpg-hidden dragging');
|
||||||
@@ -2252,14 +2253,14 @@ export function createThoughtPanel($message, thoughtsArray) {
|
|||||||
$icon.addClass('rpg-collapsed-desktop');
|
$icon.addClass('rpg-collapsed-desktop');
|
||||||
|
|
||||||
// Hide panel and show icon
|
// Hide panel and show icon
|
||||||
$thoughtPanel.fadeOut(200, function() {
|
$thoughtPanel.fadeOut(200, function () {
|
||||||
$icon.removeClass('rpg-hidden rpg-force-hide');
|
$icon.removeClass('rpg-hidden rpg-force-hide');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Icon click/tap to show panel
|
// Icon click/tap to show panel
|
||||||
const handleThoughtIconTap = function(e) {
|
const handleThoughtIconTap = function (e) {
|
||||||
const isMobileView = window.innerWidth <= 1000;
|
const isMobileView = window.innerWidth <= 1000;
|
||||||
const $icon = $('#rpg-thought-icon');
|
const $icon = $('#rpg-thought-icon');
|
||||||
|
|
||||||
@@ -2303,7 +2304,7 @@ export function createThoughtPanel($message, thoughtsArray) {
|
|||||||
$thoughtIcon.on('click touchend', handleThoughtIconTap);
|
$thoughtIcon.on('click touchend', handleThoughtIconTap);
|
||||||
|
|
||||||
// Add event handlers for editable thoughts in the bubble
|
// Add event handlers for editable thoughts in the bubble
|
||||||
$thoughtPanel.find('.rpg-editable').on('blur', function() {
|
$thoughtPanel.find('.rpg-editable').on('blur', function () {
|
||||||
const character = $(this).data('character');
|
const character = $(this).data('character');
|
||||||
const field = $(this).data('field');
|
const field = $(this).data('field');
|
||||||
const value = $(this).text().trim();
|
const value = $(this).text().trim();
|
||||||
@@ -2312,7 +2313,7 @@ export function createThoughtPanel($message, thoughtsArray) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add event listener for section lock icon clicks (support both click and touch)
|
// Add event listener for section lock icon clicks (support both click and touch)
|
||||||
$thoughtPanel.find('.rpg-section-lock-icon').on('click touchend', function(e) {
|
$thoughtPanel.find('.rpg-section-lock-icon').on('click touchend', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const $icon = $(this);
|
const $icon = $(this);
|
||||||
@@ -2363,7 +2364,7 @@ export function createThoughtPanel($message, thoughtsArray) {
|
|||||||
// Position stays fixed at top-left
|
// Position stays fixed at top-left
|
||||||
|
|
||||||
// Remove panel when clicking outside (mobile only)
|
// Remove panel when clicking outside (mobile only)
|
||||||
$(document).on('click.thoughtPanel', function(e) {
|
$(document).on('click.thoughtPanel', function (e) {
|
||||||
// Only hide on click outside in mobile view
|
// Only hide on click outside in mobile view
|
||||||
if (window.innerWidth <= 1000) {
|
if (window.innerWidth <= 1000) {
|
||||||
if (!$(e.target).closest('#rpg-thought-panel, #rpg-thought-icon').length) {
|
if (!$(e.target).closest('#rpg-thought-panel, #rpg-thought-icon').length) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
$userStatsContainer,
|
$userStatsContainer,
|
||||||
FALLBACK_AVATAR_DATA_URI
|
FALLBACK_AVATAR_DATA_URI
|
||||||
} from '../../core/state.js';
|
} from '../../core/state.js';
|
||||||
|
import { i18n } from '../../core/i18n.js';
|
||||||
import {
|
import {
|
||||||
saveSettings,
|
saveSettings,
|
||||||
saveChatData,
|
saveChatData,
|
||||||
@@ -273,7 +274,7 @@ export function renderUserStats() {
|
|||||||
// Check if stats bars section is locked
|
// Check if stats bars section is locked
|
||||||
const isStatsLocked = isItemLocked('userStats', 'stats');
|
const isStatsLocked = isItemLocked('userStats', 'stats');
|
||||||
const lockIcon = isStatsLocked ? '🔒' : '🔓';
|
const lockIcon = isStatsLocked ? '🔒' : '🔓';
|
||||||
const lockTitle = isStatsLocked ? 'Locked - AI cannot change stats' : 'Unlocked - AI can change stats';
|
const lockTitle = isStatsLocked ? i18n.getTranslation('userStats.statsLocked') : i18n.getTranslation('userStats.statsUnlocked');
|
||||||
const lockedClass = isStatsLocked ? ' locked' : '';
|
const lockedClass = isStatsLocked ? ' locked' : '';
|
||||||
|
|
||||||
let html = '<div class="rpg-stats-content">';
|
let html = '<div class="rpg-stats-content">';
|
||||||
@@ -286,8 +287,8 @@ export function renderUserStats() {
|
|||||||
<img src="${userPortrait}" alt="${userName}" class="rpg-user-portrait" onerror="this.style.opacity='0.5';this.onerror=null;" />
|
<img src="${userPortrait}" alt="${userName}" class="rpg-user-portrait" onerror="this.style.opacity='0.5';this.onerror=null;" />
|
||||||
<span class="rpg-user-name">${userName}</span>
|
<span class="rpg-user-name">${userName}</span>
|
||||||
${showLevel ? `<span style="opacity: 0.5;">|</span>
|
${showLevel ? `<span style="opacity: 0.5;">|</span>
|
||||||
<span class="rpg-level-label">LVL</span>
|
<span class="rpg-level-label">${i18n.getTranslation('userStats.level')}</span>
|
||||||
<span class="rpg-level-value rpg-editable" contenteditable="true" data-field="level" title="Click to edit level">${extensionSettings.level}</span>` : ''}
|
<span class="rpg-level-value rpg-editable" contenteditable="true" data-field="level" title="${i18n.getTranslation('userStats.clickToEditLevel')}">${extensionSettings.level}</span>` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -320,11 +321,11 @@ export function renderUserStats() {
|
|||||||
|
|
||||||
html += `
|
html += `
|
||||||
<div class="rpg-stat-row">
|
<div class="rpg-stat-row">
|
||||||
<span class="rpg-stat-label rpg-editable-stat-name" contenteditable="true" data-field="${stat.id}" title="Click to edit stat name">${stat.name}:</span>
|
<span class="rpg-stat-label rpg-editable-stat-name" contenteditable="true" data-field="${stat.id}" title="${i18n.getTranslation('userStats.clickToEditStatName')}">${stat.name}:</span>
|
||||||
<div class="rpg-stat-bar" style="background: ${gradient}">
|
<div class="rpg-stat-bar" style="background: ${gradient}">
|
||||||
<div class="rpg-stat-fill" style="width: ${100 - percentage}%"></div>
|
<div class="rpg-stat-fill" style="width: ${100 - percentage}%"></div>
|
||||||
</div>
|
</div>
|
||||||
<span class="rpg-stat-value rpg-editable-stat" contenteditable="true" data-field="${stat.id}" data-max="${maxValue}" data-mode="${displayMode}" title="Click to edit">${displayValue}</span>
|
<span class="rpg-stat-value rpg-editable-stat" contenteditable="true" data-field="${stat.id}" data-max="${maxValue}" data-mode="${displayMode}" title="${i18n.getTranslation('userStats.clickToEditStatValue')}">${displayValue}</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -334,7 +335,7 @@ export function renderUserStats() {
|
|||||||
if (config.statusSection.enabled) {
|
if (config.statusSection.enabled) {
|
||||||
const isMoodLocked = isItemLocked('userStats', 'status');
|
const isMoodLocked = isItemLocked('userStats', 'status');
|
||||||
const moodLockIcon = isMoodLocked ? '🔒' : '🔓';
|
const moodLockIcon = isMoodLocked ? '🔒' : '🔓';
|
||||||
const moodLockTitle = isMoodLocked ? 'Locked - AI cannot change mood' : 'Unlocked - AI can change mood';
|
const moodLockTitle = isMoodLocked ? i18n.getTranslation('userStats.moodLocked') : i18n.getTranslation('userStats.moodUnlocked');
|
||||||
const moodLockedClass = isMoodLocked ? ' locked' : '';
|
const moodLockedClass = isMoodLocked ? ' locked' : '';
|
||||||
html += '<div class="rpg-mood">';
|
html += '<div class="rpg-mood">';
|
||||||
if (showLockIcons) {
|
if (showLockIcons) {
|
||||||
@@ -342,7 +343,7 @@ export function renderUserStats() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.statusSection.showMoodEmoji) {
|
if (config.statusSection.showMoodEmoji) {
|
||||||
html += `<div class="rpg-mood-emoji rpg-editable" contenteditable="true" data-field="mood" title="Click to edit emoji">${stats.mood}</div>`;
|
html += `<div class="rpg-mood-emoji rpg-editable" contenteditable="true" data-field="mood" title="${i18n.getTranslation('userStats.clickToEditEmoji')}">${stats.mood}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render custom status fields
|
// Render custom status fields
|
||||||
@@ -368,7 +369,7 @@ export function renderUserStats() {
|
|||||||
if (config.skillsSection.enabled) {
|
if (config.skillsSection.enabled) {
|
||||||
const isSkillsLocked = isItemLocked('userStats', 'skills');
|
const isSkillsLocked = isItemLocked('userStats', 'skills');
|
||||||
const skillsLockIcon = isSkillsLocked ? '🔒' : '🔓';
|
const skillsLockIcon = isSkillsLocked ? '🔒' : '🔓';
|
||||||
const skillsLockTitle = isSkillsLocked ? 'Locked - AI cannot change skills' : 'Unlocked - AI can change skills';
|
const skillsLockTitle = isSkillsLocked ? i18n.getTranslation('userStats.skillsLocked') : i18n.getTranslation('userStats.skillsUnlocked');
|
||||||
const skillsLockedClass = isSkillsLocked ? ' locked' : '';
|
const skillsLockedClass = isSkillsLocked ? ' locked' : '';
|
||||||
let skillsValue = 'None';
|
let skillsValue = 'None';
|
||||||
// Handle JSON array format: [{name: "Art"}, {name: "Coding"}]
|
// Handle JSON array format: [{name: "Art"}, {name: "Coding"}]
|
||||||
@@ -385,7 +386,7 @@ export function renderUserStats() {
|
|||||||
}
|
}
|
||||||
html += `
|
html += `
|
||||||
<span class="rpg-skills-label">${config.skillsSection.label}:</span>
|
<span class="rpg-skills-label">${config.skillsSection.label}:</span>
|
||||||
<div class="rpg-skills-value rpg-editable" contenteditable="true" data-field="skills" title="Click to edit skills">${skillsValue}</div>
|
<div class="rpg-skills-value rpg-editable" contenteditable="true" data-field="skills" title="${i18n.getTranslation('userStats.clickToEditSkills')}">${skillsValue}</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -409,15 +410,15 @@ export function renderUserStats() {
|
|||||||
const enabledAttributes = rpgAttributes.filter(attr => attr && attr.enabled && attr.name && attr.id);
|
const enabledAttributes = rpgAttributes.filter(attr => attr && attr.enabled && attr.name && attr.id);
|
||||||
|
|
||||||
if (enabledAttributes.length > 0) {
|
if (enabledAttributes.length > 0) {
|
||||||
html += `
|
html += `
|
||||||
<div class="rpg-stats-right">
|
<div class="rpg-stats-right">
|
||||||
<div class="rpg-classic-stats">
|
<div class="rpg-classic-stats">
|
||||||
<div class="rpg-classic-stats-grid">
|
<div class="rpg-classic-stats-grid">
|
||||||
`;
|
`;
|
||||||
|
|
||||||
enabledAttributes.forEach(attr => {
|
enabledAttributes.forEach(attr => {
|
||||||
const value = extensionSettings.classicStats[attr.id] !== undefined ? extensionSettings.classicStats[attr.id] : 10;
|
const value = extensionSettings.classicStats[attr.id] !== undefined ? extensionSettings.classicStats[attr.id] : 10;
|
||||||
html += `
|
html += `
|
||||||
<div class="rpg-classic-stat" data-stat="${attr.id}">
|
<div class="rpg-classic-stat" data-stat="${attr.id}">
|
||||||
<span class="rpg-classic-stat-label">${attr.name}</span>
|
<span class="rpg-classic-stat-label">${attr.name}</span>
|
||||||
<div class="rpg-classic-stat-buttons">
|
<div class="rpg-classic-stat-buttons">
|
||||||
@@ -427,9 +428,9 @@ export function renderUserStats() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
});
|
});
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -448,7 +449,7 @@ export function renderUserStats() {
|
|||||||
// console.log('[RPG UserStats Render] ✓ HTML rendered to #rpg-user-stats container');
|
// console.log('[RPG UserStats Render] ✓ HTML rendered to #rpg-user-stats container');
|
||||||
|
|
||||||
// Add event listeners for editable stat values
|
// Add event listeners for editable stat values
|
||||||
$('.rpg-editable-stat').on('blur', function() {
|
$('.rpg-editable-stat').on('blur', function () {
|
||||||
const field = $(this).data('field');
|
const field = $(this).data('field');
|
||||||
const mode = $(this).data('mode');
|
const mode = $(this).data('mode');
|
||||||
const maxValue = parseInt($(this).data('max')) || 100;
|
const maxValue = parseInt($(this).data('max')) || 100;
|
||||||
@@ -492,7 +493,7 @@ export function renderUserStats() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add event listeners for mood/conditions editing
|
// Add event listeners for mood/conditions editing
|
||||||
$('.rpg-mood-emoji.rpg-editable').on('blur', function() {
|
$('.rpg-mood-emoji.rpg-editable').on('blur', function () {
|
||||||
const value = $(this).text().trim();
|
const value = $(this).text().trim();
|
||||||
extensionSettings.userStats.mood = value || '😐';
|
extensionSettings.userStats.mood = value || '😐';
|
||||||
|
|
||||||
@@ -504,7 +505,7 @@ export function renderUserStats() {
|
|||||||
updateMessageSwipeData();
|
updateMessageSwipeData();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.rpg-mood-conditions.rpg-editable').on('blur', function() {
|
$('.rpg-mood-conditions.rpg-editable').on('blur', function () {
|
||||||
const value = $(this).text().trim();
|
const value = $(this).text().trim();
|
||||||
const fieldKey = $(this).data('field');
|
const fieldKey = $(this).data('field');
|
||||||
extensionSettings.userStats[fieldKey] = value || 'None';
|
extensionSettings.userStats[fieldKey] = value || 'None';
|
||||||
@@ -518,7 +519,7 @@ export function renderUserStats() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add event listener for skills editing
|
// Add event listener for skills editing
|
||||||
$('.rpg-skills-value.rpg-editable').on('blur', function() {
|
$('.rpg-skills-value.rpg-editable').on('blur', function () {
|
||||||
const value = $(this).text().trim();
|
const value = $(this).text().trim();
|
||||||
extensionSettings.userStats.skills = value || 'None';
|
extensionSettings.userStats.skills = value || 'None';
|
||||||
|
|
||||||
@@ -531,7 +532,7 @@ export function renderUserStats() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add event listeners for stat name editing
|
// Add event listeners for stat name editing
|
||||||
$('.rpg-editable-stat-name').on('blur', function() {
|
$('.rpg-editable-stat-name').on('blur', function () {
|
||||||
const field = $(this).data('field');
|
const field = $(this).data('field');
|
||||||
const value = $(this).text().trim().replace(':', '');
|
const value = $(this).text().trim().replace(':', '');
|
||||||
|
|
||||||
@@ -555,7 +556,7 @@ export function renderUserStats() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add event listener for level editing
|
// Add event listener for level editing
|
||||||
$('.rpg-level-value.rpg-editable').on('blur', function() {
|
$('.rpg-level-value.rpg-editable').on('blur', function () {
|
||||||
let value = parseInt($(this).text().trim());
|
let value = parseInt($(this).text().trim());
|
||||||
if (isNaN(value) || value < 1) {
|
if (isNaN(value) || value < 1) {
|
||||||
value = 1;
|
value = 1;
|
||||||
@@ -573,15 +574,15 @@ export function renderUserStats() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Prevent line breaks in level field
|
// Prevent line breaks in level field
|
||||||
$('.rpg-level-value.rpg-editable').on('keydown', function(e) {
|
$('.rpg-level-value.rpg-editable').on('keydown', function (e) {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$(this).blur();
|
$(this).blur();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add event listener for section lock icon clicks (support both click and touch)
|
// Add event listener for section lock icon clicks (support both click and touch)
|
||||||
$('.rpg-section-lock-icon').on('click touchend', function(e) {
|
$('.rpg-section-lock-icon').on('click touchend', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const $icon = $(this);
|
const $icon = $(this);
|
||||||
@@ -594,7 +595,7 @@ export function renderUserStats() {
|
|||||||
|
|
||||||
// Update icon
|
// Update icon
|
||||||
const newIcon = !currentlyLocked ? '🔒' : '🔓';
|
const newIcon = !currentlyLocked ? '🔒' : '🔓';
|
||||||
const newTitle = !currentlyLocked ? 'Locked - AI cannot change this section' : 'Unlocked - AI can change this section';
|
const newTitle = !currentlyLocked ? i18n.getTranslation('infoBox.locked') : i18n.getTranslation('infoBox.unlocked');
|
||||||
$icon.text(newIcon);
|
$icon.text(newIcon);
|
||||||
$icon.attr('title', newTitle);
|
$icon.attr('title', newTitle);
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export function initTrackerEditor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tab switching
|
// Tab switching
|
||||||
$(document).on('click', '.rpg-editor-tab', function() {
|
$(document).on('click', '.rpg-editor-tab', function () {
|
||||||
$('.rpg-editor-tab').removeClass('active');
|
$('.rpg-editor-tab').removeClass('active');
|
||||||
$(this).addClass('active');
|
$(this).addClass('active');
|
||||||
|
|
||||||
@@ -61,51 +61,51 @@ export function initTrackerEditor() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Save button
|
// Save button
|
||||||
$(document).on('click', '#rpg-editor-save', function() {
|
$(document).on('click', '#rpg-editor-save', function () {
|
||||||
applyTrackerConfig();
|
applyTrackerConfig();
|
||||||
closeTrackerEditor();
|
closeTrackerEditor();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cancel button
|
// Cancel button
|
||||||
$(document).on('click', '#rpg-editor-cancel', function() {
|
$(document).on('click', '#rpg-editor-cancel', function () {
|
||||||
closeTrackerEditor();
|
closeTrackerEditor();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close X button
|
// Close X button
|
||||||
$(document).on('click', '#rpg-close-tracker-editor', function() {
|
$(document).on('click', '#rpg-close-tracker-editor', function () {
|
||||||
closeTrackerEditor();
|
closeTrackerEditor();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reset button
|
// Reset button
|
||||||
$(document).on('click', '#rpg-editor-reset', function() {
|
$(document).on('click', '#rpg-editor-reset', function () {
|
||||||
resetToDefaults();
|
resetToDefaults();
|
||||||
renderEditorUI();
|
renderEditorUI();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close on background click
|
// Close on background click
|
||||||
$(document).on('click', '#rpg-tracker-editor-popup', function(e) {
|
$(document).on('click', '#rpg-tracker-editor-popup', function (e) {
|
||||||
if (e.target.id === 'rpg-tracker-editor-popup') {
|
if (e.target.id === 'rpg-tracker-editor-popup') {
|
||||||
closeTrackerEditor();
|
closeTrackerEditor();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Open button
|
// Open button
|
||||||
$(document).on('click', '#rpg-open-tracker-editor', function() {
|
$(document).on('click', '#rpg-open-tracker-editor', function () {
|
||||||
openTrackerEditor();
|
openTrackerEditor();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Export button
|
// Export button
|
||||||
$(document).on('click', '#rpg-editor-export', function() {
|
$(document).on('click', '#rpg-editor-export', function () {
|
||||||
exportTrackerPreset();
|
exportTrackerPreset();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Import button
|
// Import button
|
||||||
$(document).on('click', '#rpg-editor-import', function() {
|
$(document).on('click', '#rpg-editor-import', function () {
|
||||||
importTrackerPreset();
|
importTrackerPreset();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Preset select change
|
// Preset select change
|
||||||
$(document).on('change', '#rpg-preset-select', function() {
|
$(document).on('change', '#rpg-preset-select', function () {
|
||||||
const presetId = $(this).val();
|
const presetId = $(this).val();
|
||||||
if (presetId && presetId !== getActivePresetId()) {
|
if (presetId && presetId !== getActivePresetId()) {
|
||||||
// Check if the current character had an association (either original or pending)
|
// Check if the current character had an association (either original or pending)
|
||||||
@@ -139,7 +139,7 @@ export function initTrackerEditor() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// New preset button
|
// New preset button
|
||||||
$(document).on('click', '#rpg-preset-new', function() {
|
$(document).on('click', '#rpg-preset-new', function () {
|
||||||
const name = prompt('Enter a name for the new preset:');
|
const name = prompt('Enter a name for the new preset:');
|
||||||
if (name && name.trim()) {
|
if (name && name.trim()) {
|
||||||
const newId = createPreset(name.trim());
|
const newId = createPreset(name.trim());
|
||||||
@@ -150,7 +150,7 @@ export function initTrackerEditor() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Set as default preset button
|
// Set as default preset button
|
||||||
$(document).on('click', '#rpg-preset-default', function() {
|
$(document).on('click', '#rpg-preset-default', function () {
|
||||||
const currentPresetId = getActivePresetId();
|
const currentPresetId = getActivePresetId();
|
||||||
if (currentPresetId) {
|
if (currentPresetId) {
|
||||||
setDefaultPreset(currentPresetId);
|
setDefaultPreset(currentPresetId);
|
||||||
@@ -161,7 +161,7 @@ export function initTrackerEditor() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Delete preset button
|
// Delete preset button
|
||||||
$(document).on('click', '#rpg-preset-delete', function() {
|
$(document).on('click', '#rpg-preset-delete', function () {
|
||||||
const currentPresetId = getActivePresetId();
|
const currentPresetId = getActivePresetId();
|
||||||
const presets = getPresets();
|
const presets = getPresets();
|
||||||
if (Object.keys(presets).length <= 1) {
|
if (Object.keys(presets).length <= 1) {
|
||||||
@@ -180,7 +180,7 @@ export function initTrackerEditor() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Associate preset checkbox
|
// Associate preset checkbox
|
||||||
$(document).on('change', '#rpg-preset-associate', function() {
|
$(document).on('change', '#rpg-preset-associate', function () {
|
||||||
const activePresetId = getActivePresetId();
|
const activePresetId = getActivePresetId();
|
||||||
const preset = getPreset(activePresetId);
|
const preset = getPreset(activePresetId);
|
||||||
const entityName = getCurrentEntityName();
|
const entityName = getCurrentEntityName();
|
||||||
@@ -334,20 +334,20 @@ function resetToDefaults() {
|
|||||||
extensionSettings.trackerConfig = {
|
extensionSettings.trackerConfig = {
|
||||||
userStats: {
|
userStats: {
|
||||||
customStats: [
|
customStats: [
|
||||||
{ id: 'health', name: 'Health', enabled: true, persistInHistory: false },
|
{ id: 'health', name: i18n.getTranslation('stats.health'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'satiety', name: 'Satiety', enabled: true, persistInHistory: false },
|
{ id: 'satiety', name: i18n.getTranslation('stats.satiety'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'energy', name: 'Energy', enabled: true, persistInHistory: false },
|
{ id: 'energy', name: i18n.getTranslation('stats.energy'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'hygiene', name: 'Hygiene', enabled: true, persistInHistory: false },
|
{ id: 'hygiene', name: i18n.getTranslation('stats.hygiene'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'arousal', name: 'Arousal', enabled: true, persistInHistory: false }
|
{ id: 'arousal', name: i18n.getTranslation('stats.arousal'), enabled: true, persistInHistory: false }
|
||||||
],
|
],
|
||||||
showRPGAttributes: true,
|
showRPGAttributes: true,
|
||||||
rpgAttributes: [
|
rpgAttributes: [
|
||||||
{ id: 'str', name: 'STR', enabled: true, persistInHistory: false },
|
{ id: 'str', name: i18n.getTranslation('stats.str'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'dex', name: 'DEX', enabled: true, persistInHistory: false },
|
{ id: 'dex', name: i18n.getTranslation('stats.dex'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'con', name: 'CON', enabled: true, persistInHistory: false },
|
{ id: 'con', name: i18n.getTranslation('stats.con'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'int', name: 'INT', enabled: true, persistInHistory: false },
|
{ id: 'int', name: i18n.getTranslation('stats.int'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'wis', name: 'WIS', enabled: true, persistInHistory: false },
|
{ id: 'wis', name: i18n.getTranslation('stats.wis'), enabled: true, persistInHistory: false },
|
||||||
{ id: 'cha', name: 'CHA', enabled: true, persistInHistory: false }
|
{ id: 'cha', name: i18n.getTranslation('stats.cha'), enabled: true, persistInHistory: false }
|
||||||
],
|
],
|
||||||
statusSection: {
|
statusSection: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -408,8 +408,8 @@ function resetToDefaults() {
|
|||||||
characterStats: {
|
characterStats: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
customStats: [
|
customStats: [
|
||||||
{ id: 'health', name: 'Health', enabled: true, colorLow: '#ff4444', colorHigh: '#44ff44' },
|
{ id: 'health', name: i18n.getTranslation('stats.health'), enabled: true, colorLow: '#ff4444', colorHigh: '#44ff44' },
|
||||||
{ id: 'energy', name: 'Energy', enabled: true, colorLow: '#ffaa00', colorHigh: '#44ffff' }
|
{ id: 'energy', name: i18n.getTranslation('stats.energy'), enabled: true, colorLow: '#ffaa00', colorHigh: '#44ffff' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -854,7 +854,7 @@ function renderUserStatsTab() {
|
|||||||
*/
|
*/
|
||||||
function setupUserStatsListeners() {
|
function setupUserStatsListeners() {
|
||||||
// Add stat
|
// Add stat
|
||||||
$('#rpg-add-stat').off('click').on('click', function() {
|
$('#rpg-add-stat').off('click').on('click', function () {
|
||||||
const newId = 'custom_' + Date.now();
|
const newId = 'custom_' + Date.now();
|
||||||
extensionSettings.trackerConfig.userStats.customStats.push({
|
extensionSettings.trackerConfig.userStats.customStats.push({
|
||||||
id: newId,
|
id: newId,
|
||||||
@@ -870,39 +870,39 @@ function setupUserStatsListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Remove stat
|
// Remove stat
|
||||||
$('.rpg-stat-remove').off('click').on('click', function() {
|
$('.rpg-stat-remove').off('click').on('click', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.userStats.customStats.splice(index, 1);
|
extensionSettings.trackerConfig.userStats.customStats.splice(index, 1);
|
||||||
renderUserStatsTab();
|
renderUserStatsTab();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Toggle stat
|
// Toggle stat
|
||||||
$('.rpg-stat-toggle').off('change').on('change', function() {
|
$('.rpg-stat-toggle').off('change').on('change', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.userStats.customStats[index].enabled = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.customStats[index].enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rename stat
|
// Rename stat
|
||||||
$('.rpg-stat-name').off('blur').on('blur', function() {
|
$('.rpg-stat-name').off('blur').on('blur', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.userStats.customStats[index].name = $(this).val();
|
extensionSettings.trackerConfig.userStats.customStats[index].name = $(this).val();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Change stat max value
|
// Change stat max value
|
||||||
$('.rpg-stat-max').off('blur').on('blur', function() {
|
$('.rpg-stat-max').off('blur').on('blur', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
const value = parseInt($(this).val()) || 100;
|
const value = parseInt($(this).val()) || 100;
|
||||||
extensionSettings.trackerConfig.userStats.customStats[index].maxValue = Math.max(1, value);
|
extensionSettings.trackerConfig.userStats.customStats[index].maxValue = Math.max(1, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Stats display mode toggle
|
// Stats display mode toggle
|
||||||
$('input[name="stats-display-mode"]').off('change').on('change', function() {
|
$('input[name="stats-display-mode"]').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.userStats.statsDisplayMode = $(this).val();
|
extensionSettings.trackerConfig.userStats.statsDisplayMode = $(this).val();
|
||||||
renderUserStatsTab(); // Re-render to show/hide max value fields
|
renderUserStatsTab(); // Re-render to show/hide max value fields
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add attribute
|
// Add attribute
|
||||||
$('#rpg-add-attr').off('click').on('click', function() {
|
$('#rpg-add-attr').off('click').on('click', function () {
|
||||||
// Ensure rpgAttributes array exists with defaults if needed
|
// Ensure rpgAttributes array exists with defaults if needed
|
||||||
if (!extensionSettings.trackerConfig.userStats.rpgAttributes || extensionSettings.trackerConfig.userStats.rpgAttributes.length === 0) {
|
if (!extensionSettings.trackerConfig.userStats.rpgAttributes || extensionSettings.trackerConfig.userStats.rpgAttributes.length === 0) {
|
||||||
extensionSettings.trackerConfig.userStats.rpgAttributes = [
|
extensionSettings.trackerConfig.userStats.rpgAttributes = [
|
||||||
@@ -928,64 +928,64 @@ function setupUserStatsListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Remove attribute
|
// Remove attribute
|
||||||
$('.rpg-attr-remove').off('click').on('click', function() {
|
$('.rpg-attr-remove').off('click').on('click', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.userStats.rpgAttributes.splice(index, 1);
|
extensionSettings.trackerConfig.userStats.rpgAttributes.splice(index, 1);
|
||||||
renderUserStatsTab();
|
renderUserStatsTab();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Toggle attribute
|
// Toggle attribute
|
||||||
$('.rpg-attr-toggle').off('change').on('change', function() {
|
$('.rpg-attr-toggle').off('change').on('change', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.userStats.rpgAttributes[index].enabled = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.rpgAttributes[index].enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rename attribute
|
// Rename attribute
|
||||||
$('.rpg-attr-name').off('blur').on('blur', function() {
|
$('.rpg-attr-name').off('blur').on('blur', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.userStats.rpgAttributes[index].name = $(this).val();
|
extensionSettings.trackerConfig.userStats.rpgAttributes[index].name = $(this).val();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enable/disable RPG Attributes section toggle
|
// Enable/disable RPG Attributes section toggle
|
||||||
$('#rpg-show-rpg-attrs').off('change').on('change', function() {
|
$('#rpg-show-rpg-attrs').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.userStats.showRPGAttributes = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.showRPGAttributes = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show/hide level toggle
|
// Show/hide level toggle
|
||||||
$('#rpg-show-level').off('change').on('change', function() {
|
$('#rpg-show-level').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.userStats.showLevel = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.showLevel = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Always send attributes toggle
|
// Always send attributes toggle
|
||||||
$('#rpg-always-send-attrs').off('change').on('change', function() {
|
$('#rpg-always-send-attrs').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.userStats.alwaysSendAttributes = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.alwaysSendAttributes = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Status section toggles
|
// Status section toggles
|
||||||
$('#rpg-status-enabled').off('change').on('change', function() {
|
$('#rpg-status-enabled').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.userStats.statusSection.enabled = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.statusSection.enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-mood-emoji').off('change').on('change', function() {
|
$('#rpg-mood-emoji').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.userStats.statusSection.showMoodEmoji = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.statusSection.showMoodEmoji = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-status-fields').off('blur').on('blur', function() {
|
$('#rpg-status-fields').off('blur').on('blur', function () {
|
||||||
const fields = $(this).val().split(',').map(f => f.trim()).filter(f => f);
|
const fields = $(this).val().split(',').map(f => f.trim()).filter(f => f);
|
||||||
extensionSettings.trackerConfig.userStats.statusSection.customFields = fields;
|
extensionSettings.trackerConfig.userStats.statusSection.customFields = fields;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Skills section toggles
|
// Skills section toggles
|
||||||
$('#rpg-skills-enabled').off('change').on('change', function() {
|
$('#rpg-skills-enabled').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.userStats.skillsSection.enabled = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.skillsSection.enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-skills-label').off('blur').on('blur', function() {
|
$('#rpg-skills-label').off('blur').on('blur', function () {
|
||||||
extensionSettings.trackerConfig.userStats.skillsSection.label = $(this).val();
|
extensionSettings.trackerConfig.userStats.skillsSection.label = $(this).val();
|
||||||
saveSettings();
|
saveSettings();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-skills-fields').off('blur').on('blur', function() {
|
$('#rpg-skills-fields').off('blur').on('blur', function () {
|
||||||
const fields = $(this).val().split(',').map(f => f.trim()).filter(f => f);
|
const fields = $(this).val().split(',').map(f => f.trim()).filter(f => f);
|
||||||
extensionSettings.trackerConfig.userStats.skillsSection.customFields = fields;
|
extensionSettings.trackerConfig.userStats.skillsSection.customFields = fields;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
@@ -1057,35 +1057,35 @@ function renderInfoBoxTab() {
|
|||||||
function setupInfoBoxListeners() {
|
function setupInfoBoxListeners() {
|
||||||
const widgets = extensionSettings.trackerConfig.infoBox.widgets;
|
const widgets = extensionSettings.trackerConfig.infoBox.widgets;
|
||||||
|
|
||||||
$('#rpg-widget-date').off('change').on('change', function() {
|
$('#rpg-widget-date').off('change').on('change', function () {
|
||||||
widgets.date.enabled = $(this).is(':checked');
|
widgets.date.enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-date-format').off('change').on('change', function() {
|
$('#rpg-date-format').off('change').on('change', function () {
|
||||||
widgets.date.format = $(this).val();
|
widgets.date.format = $(this).val();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-widget-weather').off('change').on('change', function() {
|
$('#rpg-widget-weather').off('change').on('change', function () {
|
||||||
widgets.weather.enabled = $(this).is(':checked');
|
widgets.weather.enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-widget-temperature').off('change').on('change', function() {
|
$('#rpg-widget-temperature').off('change').on('change', function () {
|
||||||
widgets.temperature.enabled = $(this).is(':checked');
|
widgets.temperature.enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('input[name="temp-unit"]').off('change').on('change', function() {
|
$('input[name="temp-unit"]').off('change').on('change', function () {
|
||||||
widgets.temperature.unit = $(this).val();
|
widgets.temperature.unit = $(this).val();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-widget-time').off('change').on('change', function() {
|
$('#rpg-widget-time').off('change').on('change', function () {
|
||||||
widgets.time.enabled = $(this).is(':checked');
|
widgets.time.enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-widget-location').off('change').on('change', function() {
|
$('#rpg-widget-location').off('change').on('change', function () {
|
||||||
widgets.location.enabled = $(this).is(':checked');
|
widgets.location.enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-widget-events').off('change').on('change', function() {
|
$('#rpg-widget-events').off('change').on('change', function () {
|
||||||
widgets.recentEvents.enabled = $(this).is(':checked');
|
widgets.recentEvents.enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1209,7 +1209,7 @@ function renderPresentCharactersTab() {
|
|||||||
*/
|
*/
|
||||||
function setupPresentCharactersListeners() {
|
function setupPresentCharactersListeners() {
|
||||||
// Relationships enabled toggle
|
// Relationships enabled toggle
|
||||||
$('#rpg-relationships-enabled').off('change').on('change', function() {
|
$('#rpg-relationships-enabled').off('change').on('change', function () {
|
||||||
if (!extensionSettings.trackerConfig.presentCharacters.relationships) {
|
if (!extensionSettings.trackerConfig.presentCharacters.relationships) {
|
||||||
extensionSettings.trackerConfig.presentCharacters.relationships = { enabled: true, relationshipEmojis: {} };
|
extensionSettings.trackerConfig.presentCharacters.relationships = { enabled: true, relationshipEmojis: {} };
|
||||||
}
|
}
|
||||||
@@ -1217,7 +1217,7 @@ function setupPresentCharactersListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add new relationship
|
// Add new relationship
|
||||||
$('#rpg-add-relationship').off('click').on('click', function() {
|
$('#rpg-add-relationship').off('click').on('click', function () {
|
||||||
// Ensure relationships object exists
|
// Ensure relationships object exists
|
||||||
if (!extensionSettings.trackerConfig.presentCharacters.relationships) {
|
if (!extensionSettings.trackerConfig.presentCharacters.relationships) {
|
||||||
extensionSettings.trackerConfig.presentCharacters.relationships = { enabled: true, relationshipEmojis: {} };
|
extensionSettings.trackerConfig.presentCharacters.relationships = { enabled: true, relationshipEmojis: {} };
|
||||||
@@ -1254,7 +1254,7 @@ function setupPresentCharactersListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Remove relationship
|
// Remove relationship
|
||||||
$('.rpg-remove-relationship').off('click').on('click', function() {
|
$('.rpg-remove-relationship').off('click').on('click', function () {
|
||||||
const relationship = $(this).data('relationship');
|
const relationship = $(this).data('relationship');
|
||||||
|
|
||||||
// Remove from new structure
|
// Remove from new structure
|
||||||
@@ -1275,7 +1275,7 @@ function setupPresentCharactersListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Update relationship name
|
// Update relationship name
|
||||||
$('.rpg-relationship-name').off('blur').on('blur', function() {
|
$('.rpg-relationship-name').off('blur').on('blur', function () {
|
||||||
const newName = $(this).val();
|
const newName = $(this).val();
|
||||||
const $item = $(this).closest('.rpg-relationship-item');
|
const $item = $(this).closest('.rpg-relationship-item');
|
||||||
const emoji = $item.find('.rpg-relationship-emoji').val();
|
const emoji = $item.find('.rpg-relationship-emoji').val();
|
||||||
@@ -1309,7 +1309,7 @@ function setupPresentCharactersListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Update relationship emoji
|
// Update relationship emoji
|
||||||
$('.rpg-relationship-emoji').off('blur').on('blur', function() {
|
$('.rpg-relationship-emoji').off('blur').on('blur', function () {
|
||||||
const name = $(this).closest('.rpg-relationship-item').find('.rpg-relationship-name').val();
|
const name = $(this).closest('.rpg-relationship-item').find('.rpg-relationship-name').val();
|
||||||
|
|
||||||
// Ensure structures exist
|
// Ensure structures exist
|
||||||
@@ -1326,21 +1326,21 @@ function setupPresentCharactersListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Thoughts configuration
|
// Thoughts configuration
|
||||||
$('#rpg-thoughts-enabled').off('change').on('change', function() {
|
$('#rpg-thoughts-enabled').off('change').on('change', function () {
|
||||||
if (!extensionSettings.trackerConfig.presentCharacters.thoughts) {
|
if (!extensionSettings.trackerConfig.presentCharacters.thoughts) {
|
||||||
extensionSettings.trackerConfig.presentCharacters.thoughts = {};
|
extensionSettings.trackerConfig.presentCharacters.thoughts = {};
|
||||||
}
|
}
|
||||||
extensionSettings.trackerConfig.presentCharacters.thoughts.enabled = $(this).is(':checked');
|
extensionSettings.trackerConfig.presentCharacters.thoughts.enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-thoughts-name').off('blur').on('blur', function() {
|
$('#rpg-thoughts-name').off('blur').on('blur', function () {
|
||||||
if (!extensionSettings.trackerConfig.presentCharacters.thoughts) {
|
if (!extensionSettings.trackerConfig.presentCharacters.thoughts) {
|
||||||
extensionSettings.trackerConfig.presentCharacters.thoughts = {};
|
extensionSettings.trackerConfig.presentCharacters.thoughts = {};
|
||||||
}
|
}
|
||||||
extensionSettings.trackerConfig.presentCharacters.thoughts.name = $(this).val();
|
extensionSettings.trackerConfig.presentCharacters.thoughts.name = $(this).val();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#rpg-thoughts-description').off('blur').on('blur', function() {
|
$('#rpg-thoughts-description').off('blur').on('blur', function () {
|
||||||
if (!extensionSettings.trackerConfig.presentCharacters.thoughts) {
|
if (!extensionSettings.trackerConfig.presentCharacters.thoughts) {
|
||||||
extensionSettings.trackerConfig.presentCharacters.thoughts = {};
|
extensionSettings.trackerConfig.presentCharacters.thoughts = {};
|
||||||
}
|
}
|
||||||
@@ -1348,7 +1348,7 @@ function setupPresentCharactersListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add field
|
// Add field
|
||||||
$('#rpg-add-field').off('click').on('click', function() {
|
$('#rpg-add-field').off('click').on('click', function () {
|
||||||
extensionSettings.trackerConfig.presentCharacters.customFields.push({
|
extensionSettings.trackerConfig.presentCharacters.customFields.push({
|
||||||
id: 'custom_' + Date.now(),
|
id: 'custom_' + Date.now(),
|
||||||
name: 'New Field',
|
name: 'New Field',
|
||||||
@@ -1359,14 +1359,14 @@ function setupPresentCharactersListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Remove field
|
// Remove field
|
||||||
$('.rpg-field-remove').off('click').on('click', function() {
|
$('.rpg-field-remove').off('click').on('click', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.presentCharacters.customFields.splice(index, 1);
|
extensionSettings.trackerConfig.presentCharacters.customFields.splice(index, 1);
|
||||||
renderPresentCharactersTab();
|
renderPresentCharactersTab();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Move field up
|
// Move field up
|
||||||
$('.rpg-field-move-up').off('click').on('click', function() {
|
$('.rpg-field-move-up').off('click').on('click', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
const fields = extensionSettings.trackerConfig.presentCharacters.customFields;
|
const fields = extensionSettings.trackerConfig.presentCharacters.customFields;
|
||||||
@@ -1376,7 +1376,7 @@ function setupPresentCharactersListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Move field down
|
// Move field down
|
||||||
$('.rpg-field-move-down').off('click').on('click', function() {
|
$('.rpg-field-move-down').off('click').on('click', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
const fields = extensionSettings.trackerConfig.presentCharacters.customFields;
|
const fields = extensionSettings.trackerConfig.presentCharacters.customFields;
|
||||||
if (index < fields.length - 1) {
|
if (index < fields.length - 1) {
|
||||||
@@ -1386,25 +1386,25 @@ function setupPresentCharactersListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Toggle field
|
// Toggle field
|
||||||
$('.rpg-field-toggle').off('change').on('change', function() {
|
$('.rpg-field-toggle').off('change').on('change', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.presentCharacters.customFields[index].enabled = $(this).is(':checked');
|
extensionSettings.trackerConfig.presentCharacters.customFields[index].enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rename field
|
// Rename field
|
||||||
$('.rpg-field-label').off('blur').on('blur', function() {
|
$('.rpg-field-label').off('blur').on('blur', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.presentCharacters.customFields[index].name = $(this).val();
|
extensionSettings.trackerConfig.presentCharacters.customFields[index].name = $(this).val();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update description
|
// Update description
|
||||||
$('.rpg-field-placeholder').off('blur').on('blur', function() {
|
$('.rpg-field-placeholder').off('blur').on('blur', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.presentCharacters.customFields[index].description = $(this).val();
|
extensionSettings.trackerConfig.presentCharacters.customFields[index].description = $(this).val();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Character stats toggle
|
// Character stats toggle
|
||||||
$('#rpg-char-stats-enabled').off('change').on('change', function() {
|
$('#rpg-char-stats-enabled').off('change').on('change', function () {
|
||||||
if (!extensionSettings.trackerConfig.presentCharacters.characterStats) {
|
if (!extensionSettings.trackerConfig.presentCharacters.characterStats) {
|
||||||
extensionSettings.trackerConfig.presentCharacters.characterStats = { enabled: false, customStats: [] };
|
extensionSettings.trackerConfig.presentCharacters.characterStats = { enabled: false, customStats: [] };
|
||||||
}
|
}
|
||||||
@@ -1412,7 +1412,7 @@ function setupPresentCharactersListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add character stat
|
// Add character stat
|
||||||
$('#rpg-add-char-stat').off('click').on('click', function() {
|
$('#rpg-add-char-stat').off('click').on('click', function () {
|
||||||
if (!extensionSettings.trackerConfig.presentCharacters.characterStats) {
|
if (!extensionSettings.trackerConfig.presentCharacters.characterStats) {
|
||||||
extensionSettings.trackerConfig.presentCharacters.characterStats = { enabled: false, customStats: [] };
|
extensionSettings.trackerConfig.presentCharacters.characterStats = { enabled: false, customStats: [] };
|
||||||
}
|
}
|
||||||
@@ -1428,20 +1428,20 @@ function setupPresentCharactersListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Remove character stat
|
// Remove character stat
|
||||||
$('.rpg-char-stat-remove').off('click').on('click', function() {
|
$('.rpg-char-stat-remove').off('click').on('click', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.presentCharacters.characterStats.customStats.splice(index, 1);
|
extensionSettings.trackerConfig.presentCharacters.characterStats.customStats.splice(index, 1);
|
||||||
renderPresentCharactersTab();
|
renderPresentCharactersTab();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Toggle character stat
|
// Toggle character stat
|
||||||
$('.rpg-char-stat-toggle').off('change').on('change', function() {
|
$('.rpg-char-stat-toggle').off('change').on('change', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.presentCharacters.characterStats.customStats[index].enabled = $(this).is(':checked');
|
extensionSettings.trackerConfig.presentCharacters.characterStats.customStats[index].enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rename character stat
|
// Rename character stat
|
||||||
$('.rpg-char-stat-label').off('blur').on('blur', function() {
|
$('.rpg-char-stat-label').off('blur').on('blur', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.presentCharacters.characterStats.customStats[index].name = $(this).val();
|
extensionSettings.trackerConfig.presentCharacters.characterStats.customStats[index].name = $(this).val();
|
||||||
});
|
});
|
||||||
@@ -1637,70 +1637,70 @@ function setupHistoryPersistenceListeners() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Main toggle
|
// Main toggle
|
||||||
$('#rpg-history-persistence-enabled').off('change').on('change', function() {
|
$('#rpg-history-persistence-enabled').off('change').on('change', function () {
|
||||||
extensionSettings.historyPersistence.enabled = $(this).is(':checked');
|
extensionSettings.historyPersistence.enabled = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send All Enabled on Refresh toggle
|
// Send All Enabled on Refresh toggle
|
||||||
$('#rpg-history-send-all-enabled').off('change').on('change', function() {
|
$('#rpg-history-send-all-enabled').off('change').on('change', function () {
|
||||||
extensionSettings.historyPersistence.sendAllEnabledOnRefresh = $(this).is(':checked');
|
extensionSettings.historyPersistence.sendAllEnabledOnRefresh = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Message count
|
// Message count
|
||||||
$('#rpg-history-message-count').off('change').on('change', function() {
|
$('#rpg-history-message-count').off('change').on('change', function () {
|
||||||
extensionSettings.historyPersistence.messageCount = parseInt($(this).val()) || 0;
|
extensionSettings.historyPersistence.messageCount = parseInt($(this).val()) || 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Injection position
|
// Injection position
|
||||||
$('#rpg-history-injection-position').off('change').on('change', function() {
|
$('#rpg-history-injection-position').off('change').on('change', function () {
|
||||||
extensionSettings.historyPersistence.injectionPosition = $(this).val();
|
extensionSettings.historyPersistence.injectionPosition = $(this).val();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Context preamble
|
// Context preamble
|
||||||
$('#rpg-history-context-preamble').off('blur').on('blur', function() {
|
$('#rpg-history-context-preamble').off('blur').on('blur', function () {
|
||||||
extensionSettings.historyPersistence.contextPreamble = $(this).val();
|
extensionSettings.historyPersistence.contextPreamble = $(this).val();
|
||||||
});
|
});
|
||||||
|
|
||||||
// User Stats toggles
|
// User Stats toggles
|
||||||
$('.rpg-history-stat-toggle').off('change').on('change', function() {
|
$('.rpg-history-stat-toggle').off('change').on('change', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.userStats.customStats[index].persistInHistory = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.customStats[index].persistInHistory = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Status section
|
// Status section
|
||||||
$('#rpg-history-status').off('change').on('change', function() {
|
$('#rpg-history-status').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.userStats.statusSection.persistInHistory = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.statusSection.persistInHistory = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Skills section
|
// Skills section
|
||||||
$('#rpg-history-skills').off('change').on('change', function() {
|
$('#rpg-history-skills').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.userStats.skillsSection.persistInHistory = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.skillsSection.persistInHistory = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Inventory
|
// Inventory
|
||||||
$('#rpg-history-inventory').off('change').on('change', function() {
|
$('#rpg-history-inventory').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.userStats.inventoryPersistInHistory = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.inventoryPersistInHistory = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quests
|
// Quests
|
||||||
$('#rpg-history-quests').off('change').on('change', function() {
|
$('#rpg-history-quests').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.userStats.questsPersistInHistory = $(this).is(':checked');
|
extensionSettings.trackerConfig.userStats.questsPersistInHistory = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Info Box widget toggles
|
// Info Box widget toggles
|
||||||
$('.rpg-history-widget-toggle').off('change').on('change', function() {
|
$('.rpg-history-widget-toggle').off('change').on('change', function () {
|
||||||
const widgetId = $(this).data('widget');
|
const widgetId = $(this).data('widget');
|
||||||
extensionSettings.trackerConfig.infoBox.widgets[widgetId].persistInHistory = $(this).is(':checked');
|
extensionSettings.trackerConfig.infoBox.widgets[widgetId].persistInHistory = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Present Characters field toggles
|
// Present Characters field toggles
|
||||||
$('.rpg-history-charfield-toggle').off('change').on('change', function() {
|
$('.rpg-history-charfield-toggle').off('change').on('change', function () {
|
||||||
const index = $(this).data('index');
|
const index = $(this).data('index');
|
||||||
extensionSettings.trackerConfig.presentCharacters.customFields[index].persistInHistory = $(this).is(':checked');
|
extensionSettings.trackerConfig.presentCharacters.customFields[index].persistInHistory = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Thoughts
|
// Thoughts
|
||||||
$('#rpg-history-thoughts').off('change').on('change', function() {
|
$('#rpg-history-thoughts').off('change').on('change', function () {
|
||||||
extensionSettings.trackerConfig.presentCharacters.thoughts.persistInHistory = $(this).is(':checked');
|
extensionSettings.trackerConfig.presentCharacters.thoughts.persistInHistory = $(this).is(':checked');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user