fix: improve mobile UI layout and interaction handling

- Add mobile-specific height constraints for input buttons
- Fix message alignment to left for better readability
- Change click to mousedown for better mobile responsiveness
- Adjust top bar grid columns for mobile layout
- Update view type identifier to 'ai-agent-main-view'
- Standardize quote style to double quotes across config files
This commit is contained in:
Andrew Beal 2025-11-04 22:51:22 +00:00
parent a0afcdd0d0
commit 4dcce63bce
9 changed files with 85 additions and 53 deletions

View file

@ -228,6 +228,7 @@
.message-container {
display: flex;
text-align: left;
margin: 0;
}
@ -270,6 +271,7 @@
}
.streaming-content {
justify-content: left;
min-height: 1em; /* Ensure the element exists for binding */
}

View file

@ -347,6 +347,10 @@
transition-duration: 0.5s;
}
:global(.is-mobile) #user-instruction-button {
max-height: 2rem;
}
#user-instruction-button.instruction-active {
box-shadow: 0px 0px 4px 1px var(--color-accent);
}
@ -374,6 +378,10 @@
white-space: pre-wrap;
}
:global(.is-mobile) #input-field {
align-content: end;
}
#input-field:focus {
border-color: var(--color-accent);
box-shadow: 0px 0px 4px 1px var(--color-accent);
@ -416,6 +424,10 @@
transition-duration: 0.5s;
}
:global(.is-mobile) #edit-mode-button {
max-height: 2rem;
}
#submit-button {
grid-row: 3;
grid-column: 8;
@ -427,6 +439,10 @@
background-color: var(--interactive-accent);
}
:global(.is-mobile) #submit-button {
max-height: 2rem;
}
#submit-button:not(:disabled):hover {
cursor: pointer;
background-color: var(--interactive-accent-hover);

View file

@ -1,11 +1,11 @@
<script lang="ts">
import { basename } from 'path-browserify';
import type { ISearchState, SearchStateStore } from 'Stores/SearchStateStore';
import { tick } from 'svelte';
import { setIcon } from 'obsidian';
import { SearchTrigger } from 'Enums/SearchTrigger';
import { Resolve } from 'Services/DependencyService';
import { Services } from 'Services/Services';
import { basename } from "path-browserify";
import type { ISearchState, SearchStateStore } from "Stores/SearchStateStore";
import { tick } from "svelte";
import { setIcon } from "obsidian";
import { SearchTrigger } from "Enums/SearchTrigger";
import { Resolve } from "Services/DependencyService";
import { Services } from "Services/Services";
export let searchState: ISearchState;
export let onResultAccept: () => void;
@ -35,13 +35,13 @@
function getIconName(trigger: SearchTrigger | null): string {
switch(trigger) {
case SearchTrigger.File:
return 'file-text';
return "file-text";
case SearchTrigger.Folder:
return 'folder';
return "folder";
case SearchTrigger.Tag:
return 'tag';
return "tag";
default:
return 'file-text';
return "file-text";
}
}
@ -58,9 +58,9 @@
const selectedIndex = searchState.results.indexOf(searchState.selectedResult);
if (selectedIndex !== -1 && resultElements[selectedIndex]) {
resultElements[selectedIndex]?.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
inline: 'nearest'
behavior: "smooth",
block: "nearest",
inline: "nearest"
});
}
});
@ -78,7 +78,7 @@
bind:this={resultElements[index]}
style:background-color={searchResult === searchState.selectedResult ? "var(--interactive-accent)" : "transparent"}
on:mouseenter={() => searchStateStore.setSelectedResult(index)}
on:click={onResultAccept}
on:mousedown={onResultAccept}
on:keydown={() => {}}>
<div class="input-search-result-icon" bind:this={iconElements[index]}></div>
<div class="input-search-result-title">{basename(searchResult)}</div>
@ -145,4 +145,8 @@
font-size: var(--font-smallest);
color: var(--text-muted);
}
:global(.is-mobile) .input-search-result-container[aria-selected="true"] {
background-color: transparent !important;
}
</style>

View file

@ -142,6 +142,10 @@
border-radius: var(--radius-m);
}
:global(.is-mobile) .top-bar-content {
grid-template-columns: var(--size-4-1) auto auto auto auto auto auto 1fr 0fr auto var(--size-4-1);
}
.top-bar-divider {
width: var(--divider-width);
height: auto;
@ -149,6 +153,10 @@
margin: var(--size-4-2) var(--size-4-3);
}
:global(.is-mobile) .top-bar-divider {
margin: 0;
}
#new-conversation-button {
grid-row: 1;
grid-column: 2;

View file

@ -159,7 +159,7 @@
style:background-color={selectedInstruction === index ? "var(--interactive-accent)" : "transparent"}
bind:this={instructionsElements[index]}
on:mouseenter={() => selectedInstruction = index}
on:click={handleInstructionSelect}
on:mousedown={handleInstructionSelect}
on:keydown={() => {}}>
<div class="user-instruction-title">{basename(userInstruction)}</div>
{#if userInstruction !== basename(userInstruction)}
@ -236,4 +236,8 @@
#user-instruction-link:hover {
text-decoration: underline;
}
:global(.is-mobile) .user-instruction-container[aria-selected="true"] {
background-color: transparent !important;
}
</style>

View file

@ -6,7 +6,7 @@ import type { StatusBarService } from 'Services/StatusBarService';
import { Resolve } from 'Services/DependencyService';
import { Services } from 'Services/Services';
export const VIEW_TYPE_MAIN = 'main-view';
export const VIEW_TYPE_MAIN = 'ai-agent-main-view';
export class MainView extends ItemView {

View file

@ -2,8 +2,6 @@ import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
import { copyFileSync, mkdirSync, existsSync, readdirSync, statSync } from "fs";
import path, { join } from "path";
import esbuildSvelte from 'esbuild-svelte';
import { sveltePreprocess } from 'svelte-preprocess';

View file

@ -2,11 +2,11 @@
/* Main View Customization */
/* ============================== */
.workspace-leaf-content[data-type="main-view"] {
.workspace-leaf-content[data-type="ai-agent-main-view"] {
background-color: var(--background-secondary);
}
.workspace-leaf-content[data-type="main-view"] .view-content {
.workspace-leaf-content[data-type="ai-agent-main-view"] .view-content {
align-self: center;
max-width: 1000px;
background-color: var(--background-secondary);

View file

@ -1,6 +1,6 @@
import { defineConfig } from 'vitest/config';
import * as path from 'path-browserify';
import { fileURLToPath } from 'url';
import { defineConfig } from "vitest/config";
import * as path from "path-browserify";
import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
@ -8,50 +8,50 @@ export default defineConfig({
plugins: [],
resolve: {
alias: {
'obsidian': path.resolve(__dirname, '__mocks__/obsidian.ts'),
"obsidian": path.resolve(__dirname, "__mocks__/obsidian.ts"),
// Support TypeScript path mapping from tsconfig
'Helpers': path.resolve(__dirname, 'Helpers'),
'Enums': path.resolve(__dirname, 'Enums'),
'Services': path.resolve(__dirname, 'Services'),
'Conversations': path.resolve(__dirname, 'Conversations'),
'AIClasses': path.resolve(__dirname, 'AIClasses'),
'Components': path.resolve(__dirname, 'Components'),
'Stores': path.resolve(__dirname, 'Stores'),
'Views': path.resolve(__dirname, 'Views'),
'Modals': path.resolve(__dirname, 'Modals')
"Helpers": path.resolve(__dirname, "Helpers"),
"Enums": path.resolve(__dirname, "Enums"),
"Services": path.resolve(__dirname, "Services"),
"Conversations": path.resolve(__dirname, "Conversations"),
"AIClasses": path.resolve(__dirname, "AIClasses"),
"Components": path.resolve(__dirname, "Components"),
"Stores": path.resolve(__dirname, "Stores"),
"Views": path.resolve(__dirname, "Views"),
"Modals": path.resolve(__dirname, "Modals")
}
},
test: {
// Use happy-dom for faster DOM simulation
environment: 'happy-dom',
environment: "happy-dom",
// Test file patterns
include: ['__tests__/**/*.{test,spec}.{js,ts}'],
include: ["__tests__/**/*.{test,spec}.{js,ts}"],
// Setup files to run before each test file
setupFiles: ['__tests__/setup.ts'],
setupFiles: ["__tests__/setup.ts"],
// Coverage configuration
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
provider: "v8",
reporter: ["text", "json", "html"],
include: [
'Services/**/*.ts',
'AIClasses/**/*.ts',
'Helpers/**/*.ts',
'Conversations/**/*.ts',
'Components/**/*.svelte',
'Enums/**/*.ts',
'Stores/**/*.ts'
"Services/**/*.ts",
"AIClasses/**/*.ts",
"Helpers/**/*.ts",
"Conversations/**/*.ts",
"Components/**/*.svelte",
"Enums/**/*.ts",
"Stores/**/*.ts"
],
exclude: [
'**/*.test.ts',
'**/*.spec.ts',
'node_modules/**',
'__tests__/**',
'main.ts',
'Views/**',
'Modals/**'
"**/*.test.ts",
"**/*.spec.ts",
"node_modules/**",
"__tests__/**",
"main.ts",
"Views/**",
"Modals/**"
],
thresholds: {
lines: 70,