mirror of
https://github.com/andy-stack/vaultkeeper-ai.git
synced 2026-07-22 06:42:03 +00:00
feat: add mobile drawer auto-hide when keyboard is active
Implement optional drawer element hiding on mobile devices when the chat input is focused, providing more screen space for the on-screen keyboard. Elements smoothly animate away on focus and restore on blur. Includes new setting in Advanced Settings section and updates Anthropic SDK to 0.91.1.
This commit is contained in:
parent
b21207adcf
commit
9ca4f6f4f8
8 changed files with 163 additions and 22 deletions
|
|
@ -24,6 +24,7 @@
|
|||
import type { IPrompt } from "AIPrompts/IPrompt";
|
||||
import type { SettingsService } from "Services/SettingsService";
|
||||
import { ChatMode, chatModeAllowsEdits, iconForChatMode } from "Enums/ChatMode";
|
||||
import { hideDrawerElements, restoreDrawerElements } from "Helpers/ElementHelper";
|
||||
|
||||
export let attachments: Attachment[] = [];
|
||||
|
||||
|
|
@ -82,7 +83,8 @@
|
|||
});
|
||||
|
||||
function checkStacked() {
|
||||
if (textareaElement.textContent.trim() === "") {
|
||||
// Mobile already uses the 'stacked' layout
|
||||
if (Platform.isMobile || textareaElement.textContent.trim() === "") {
|
||||
stacked = false;
|
||||
return;
|
||||
}
|
||||
|
|
@ -503,8 +505,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
function handleFocusIn() {
|
||||
if (Platform.isMobile && settingsService.settings.hideDrawerElements) {
|
||||
hideDrawerElements();
|
||||
}
|
||||
}
|
||||
|
||||
function handleFocusOut() {
|
||||
searchStateStore.resetSearch();
|
||||
if (Platform.isMobile && settingsService.settings.hideDrawerElements) {
|
||||
restoreDrawerElements();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
@ -565,6 +576,7 @@
|
|||
on:dragleave={handleDragLeave}
|
||||
on:click={handleCursorPositionChange}
|
||||
on:keyup={handleCursorPositionChange}
|
||||
on:focus={handleFocusIn}
|
||||
on:focusout={handleFocusOut}
|
||||
data-placeholder={inputPlaceholder}
|
||||
role="textbox"
|
||||
|
|
|
|||
|
|
@ -84,6 +84,10 @@ export enum Copy {
|
|||
TooltipLearnMoreFileMonitoring = "Learn more in Plugin Guide",
|
||||
TooltipAccessMemories = "View Memories",
|
||||
|
||||
SettingAdvancedSettings = "Advanced Settings",
|
||||
SettingHideDrawerElements = "Hide Drawer Elements",
|
||||
SettingHideDrawerElementsDesc = "Hide side drawer elements on mobile when typing. This provides more space when an on screen keyboard is used. The elements will reappear when the chat input is unfocused.",
|
||||
|
||||
SettingQuickActions = "Quick Actions",
|
||||
SettingEnableContextMenuActions = "Enable Context Menu Actions",
|
||||
SettingEnableContextMenuActionsDesc = "Show quick actions in the right-click editor context menu.",
|
||||
|
|
|
|||
|
|
@ -17,4 +17,66 @@ export function setElementIcon(element: HTMLDivElement, iconName: string) {
|
|||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function hideDrawerElements() {
|
||||
for (const element of getDrawerElements()) {
|
||||
if ("vaultKeeperHidden" in element.dataset) continue;
|
||||
|
||||
const computed = getComputedStyle(element);
|
||||
element.dataset.vaultKeeperHidden = String(element.scrollHeight);
|
||||
element.dataset.vaultKeeperPaddingTop = computed.paddingTop;
|
||||
element.dataset.vaultKeeperPaddingBottom = computed.paddingBottom;
|
||||
|
||||
element.setCssProps({
|
||||
"--vaultKeeper-drawer-height": element.scrollHeight + "px",
|
||||
"--vaultKeeper-drawer-padding-top": computed.paddingTop,
|
||||
"--vaultKeeper-drawer-padding-bottom": computed.paddingBottom,
|
||||
});
|
||||
element.addClass("vaultKeeper-drawer-hiding");
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
element.removeClass("vaultKeeper-drawer-hiding");
|
||||
element.addClass("vaultKeeper-drawer-collapsed");
|
||||
});
|
||||
|
||||
element.addEventListener("transitionend", () => {
|
||||
element.removeClass("vaultKeeper-drawer-collapsed");
|
||||
element.addClass("vaultKeeper-drawer-hidden");
|
||||
}, { once: true });
|
||||
}
|
||||
}
|
||||
|
||||
export function restoreDrawerElements() {
|
||||
for (const element of getDrawerElements()) {
|
||||
if (!("vaultKeeperHidden" in element.dataset)) continue;
|
||||
|
||||
const targetHeight = element.dataset.vaultKeeperHidden ?? "0";
|
||||
const paddingTop = element.dataset.vaultKeeperPaddingTop ?? "0";
|
||||
const paddingBottom = element.dataset.vaultKeeperPaddingBottom ?? "0";
|
||||
delete element.dataset.vaultKeeperHidden;
|
||||
delete element.dataset.vaultKeeperPaddingTop;
|
||||
delete element.dataset.vaultKeeperPaddingBottom;
|
||||
|
||||
element.setCssProps({
|
||||
"--vaultKeeper-drawer-height": targetHeight + "px",
|
||||
"--vaultKeeper-drawer-padding-top": paddingTop,
|
||||
"--vaultKeeper-drawer-padding-bottom": paddingBottom,
|
||||
});
|
||||
element.removeClass("vaultKeeper-drawer-hidden");
|
||||
element.addClass("vaultKeeper-drawer-restoring");
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
element.removeClass("vaultKeeper-drawer-restoring");
|
||||
element.addClass("vaultKeeper-drawer-expanding");
|
||||
});
|
||||
|
||||
element.addEventListener("transitionend", () => {
|
||||
element.removeClass("vaultKeeper-drawer-expanding");
|
||||
}, { once: true });
|
||||
}
|
||||
}
|
||||
|
||||
function getDrawerElements(): NodeListOf<HTMLElement> {
|
||||
return activeDocument.querySelectorAll<HTMLElement>(".workspace-drawer-header, .workspace-drawer-tab-options");
|
||||
}
|
||||
|
|
@ -30,7 +30,9 @@ const DEFAULT_SETTINGS: IVaultkeeperAISettings = {
|
|||
enableWebViewer: false,
|
||||
|
||||
enableContextMenuActions: true,
|
||||
enableToolbarActions: true
|
||||
enableToolbarActions: true,
|
||||
|
||||
hideDrawerElements: true
|
||||
}
|
||||
|
||||
export interface IVaultkeeperAISettings {
|
||||
|
|
@ -61,6 +63,8 @@ export interface IVaultkeeperAISettings {
|
|||
|
||||
enableContextMenuActions: boolean;
|
||||
enableToolbarActions: boolean;
|
||||
|
||||
hideDrawerElements: boolean;
|
||||
}
|
||||
|
||||
export class SettingsService {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,3 @@
|
|||
/* ============================== */
|
||||
/* Mobile Drawer Full Width */
|
||||
/* ============================== */
|
||||
|
||||
body:not(.is-tablet) .workspace-drawer.mod-right {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ============================== */
|
||||
/* Main View Customization */
|
||||
/* ============================== */
|
||||
|
|
@ -22,6 +13,56 @@ body:not(.is-tablet) .workspace-drawer.mod-right {
|
|||
padding-top: 0;
|
||||
}
|
||||
|
||||
/* ============================== */
|
||||
/* Mobile Drawer Full Width */
|
||||
/* ============================== */
|
||||
|
||||
body:not(.is-tablet) .workspace-drawer.mod-right {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ============================== */
|
||||
/* Drawer element collapse animation */
|
||||
/* ============================== */
|
||||
|
||||
.vaultKeeper-drawer-hiding {
|
||||
overflow: hidden;
|
||||
height: var(--vaultKeeper-drawer-height);
|
||||
padding-top: var(--vaultKeeper-drawer-padding-top);
|
||||
padding-bottom: var(--vaultKeeper-drawer-padding-bottom);
|
||||
transition: height 0.25s ease, padding-top 0.25s ease, padding-bottom 0.25s ease;
|
||||
}
|
||||
|
||||
.vaultKeeper-drawer-collapsed {
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
transition: height 0.25s ease, padding-top 0.25s ease, padding-bottom 0.25s ease;
|
||||
}
|
||||
|
||||
.vaultKeeper-drawer-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vaultKeeper-drawer-restoring {
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
height: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
transition: height 0.25s ease, padding-top 0.25s ease, padding-bottom 0.25s ease;
|
||||
}
|
||||
|
||||
.vaultKeeper-drawer-expanding {
|
||||
overflow: hidden;
|
||||
height: var(--vaultKeeper-drawer-height);
|
||||
padding-top: var(--vaultKeeper-drawer-padding-top);
|
||||
padding-bottom: var(--vaultKeeper-drawer-padding-bottom);
|
||||
transition: height 0.25s ease, padding-top 0.25s ease, padding-bottom 0.25s ease;
|
||||
}
|
||||
|
||||
/* ============================== */
|
||||
/* Quick Actions Notice */
|
||||
/* ============================== */
|
||||
|
|
|
|||
|
|
@ -303,6 +303,24 @@ export class VaultkeeperAISettingTab extends PluginSettingTab {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
/* Advanced Settings Header */
|
||||
new Setting(containerEl)
|
||||
.setHeading()
|
||||
.setName(Copy.SettingAdvancedSettings);
|
||||
|
||||
/* Hide Drawer Elements */
|
||||
new Setting(containerEl)
|
||||
.setName(Copy.SettingHideDrawerElements)
|
||||
.setDesc(Copy.SettingHideDrawerElementsDesc)
|
||||
.addToggle(toggle => {
|
||||
toggle
|
||||
.setValue(this.settingsService.settings.hideDrawerElements)
|
||||
.onChange(async (value) => {
|
||||
this.settingsService.settings.hideDrawerElements = value;
|
||||
await this.settingsService.saveSettings();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private populateModelDropdown(dropdown: DropdownComponent, providerFilter?: AIProvider): void {
|
||||
|
|
|
|||
20
package-lock.json
generated
20
package-lock.json
generated
|
|
@ -9,7 +9,7 @@
|
|||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.91.0",
|
||||
"@anthropic-ai/sdk": "^0.91.1",
|
||||
"@google/genai": "^1.50.1",
|
||||
"@shikijs/rehype": "^4.0.2",
|
||||
"core-js": "^3.49.0",
|
||||
|
|
@ -64,9 +64,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@anthropic-ai/sdk": {
|
||||
"version": "0.91.0",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.0.tgz",
|
||||
"integrity": "sha512-hybd/DOI3ujG4gZyqqcWnSekYxkdjr1JbZYqP2Lb4AmcsU6HCTHSrTOgqedPSsQAruBVucHNAoD1vTQnpPzedw==",
|
||||
"version": "0.91.1",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz",
|
||||
"integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"json-schema-to-ts": "^3.1.1"
|
||||
|
|
@ -4196,9 +4196,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-json-schema-validator/node_modules/ajv": {
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
|
||||
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
|
||||
"version": "8.20.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
|
||||
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
@ -6788,9 +6788,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/json-schema-migrate/node_modules/ajv": {
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
|
||||
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
|
||||
"version": "8.20.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
|
||||
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
"vitest": "^4.1.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.91.0",
|
||||
"@anthropic-ai/sdk": "^0.91.1",
|
||||
"@google/genai": "^1.50.1",
|
||||
"@shikijs/rehype": "^4.0.2",
|
||||
"core-js": "^3.49.0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue