Skip to content

Commit 6361ef2

Browse files
authored
Merge pull request #63 from beekeeper-studio/fix/keyboard-focus-and-onboarding-screen
Fix keyboard focus and onboarding screen UI
2 parents 7a37682 + 98ff582 commit 6361ef2

21 files changed

+240
-53
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"@beekeeperstudio/plugin": "^1.4.0",
2323
"@langchain/core": "^0.3.61",
2424
"@material-symbols/font-400": "^0.31.2",
25+
"@pdanpdan/vue-keyboard-trap": "^1.2.0",
2526
"ai": "^4.3.16",
2627
"highlight.js": "^11.11.1",
2728
"langchain": "^0.3.19",

src/App.vue

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,20 @@
44
<h1>AI Shell</h1>
55
<div class="progress-bar"></div>
66
</div>
7-
<OnboardingScreen v-else-if="page === 'onboarding'" @submit="submitOnboardingScreen" />
8-
<ChatInterface v-else-if="page === 'chat-interface'" :initialMessages="messages" :openaiApiKey="openaiApiKey"
7+
<ChatInterface v-if="page === 'chat-interface'" :initialMessages="messages" :openaiApiKey="openaiApiKey"
98
:anthropicApiKey="anthropicApiKey" :googleApiKey="googleApiKey" @manage-models="handleManageModels"
109
@open-configuration="handleOpenConfiguration" />
11-
<div id="configuration-popover" :class="{ active: showConfiguration }">
10+
<div id="configuration-popover" :class="{ active: showConfiguration }" v-kbd-trap.autofocus="showConfiguration">
1211
<Configuration :reactivePage="configurationPage" @close="closeConfiguration" />
1312
</div>
13+
<div class="onboarding-screen-popover-container" v-if="showOnboarding">
14+
<div class="onboarding-screen-popover" v-kbd-trap="true">
15+
<button class="btn close-btn" @click="closeOnboardingScreen">
16+
<span class="material-symbols-outlined">close</span>
17+
</button>
18+
<OnboardingScreen @submit="closeOnboardingScreen" @open-provider-config="closeOnboardingScreenAndOpenProviderConfig" />
19+
</div>
20+
</div>
1421
</div>
1522
</template>
1623

@@ -27,7 +34,7 @@ import Configuration, {
2734
import OnboardingScreen from "./components/OnboardingScreen.vue";
2835
import { getData, notify } from "@beekeeperstudio/plugin";
2936
30-
type Page = "starting" | "onboarding" | "chat-interface";
37+
type Page = "starting" | "chat-interface";
3138
3239
export default {
3340
components: {
@@ -39,6 +46,7 @@ export default {
3946
data() {
4047
return {
4148
page: "starting" as Page,
49+
showOnboarding: false,
4250
showConfiguration: false,
4351
error: "" as unknown,
4452
showLoading: false,
@@ -59,13 +67,12 @@ export default {
5967
await this.initialize();
6068
await this.$nextTick();
6169
62-
if (this.isFirstTimeUser && this.apiKeyExists) {
63-
this.page = "chat-interface";
64-
} else if (this.isFirstTimeUser) {
65-
this.page = "onboarding";
66-
} else {
67-
this.page = "chat-interface";
70+
if (this.isFirstTimeUser && !this.apiKeyExists) {
71+
this.showOnboarding = true;
6872
}
73+
74+
this.page = "chat-interface";
75+
6976
} catch (e) {
7077
this.showConfiguration = true;
7178
this.error = e;
@@ -94,14 +101,25 @@ export default {
94101
...mapActions(useConfigurationStore, ["configure"]),
95102
...mapActions(useInternalDataStore, ["setInternal"]),
96103
...mapActions(useChatStore, ["initialize"]),
97-
submitOnboardingScreen() {
104+
closeOnboardingScreen() {
105+
this.showOnboarding = false;
98106
this.page = "chat-interface";
99107
this.setInternal("isFirstTimeUser", false);
100108
},
101-
handleManageModels() {
109+
async closeOnboardingScreenAndOpenProviderConfig() {
110+
this.closeOnboardingScreen();
111+
this.openModelsConfig();
112+
await this.$nextTick();
113+
const apiKeys = document.querySelector("#providers-configuration-api-keys");
114+
apiKeys?.scrollIntoView();
115+
},
116+
openModelsConfig() {
102117
this.configurationPage = "models";
103118
this.showConfiguration = true;
104119
},
120+
handleManageModels() {
121+
this.openModelsConfig();
122+
},
105123
handleOpenConfiguration() {
106124
this.configurationPage = "general";
107125
this.showConfiguration = true;

src/assets/styles/_base.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,5 @@ a {
6464
}
6565

6666
:focus-visible {
67-
outline-color: transparent;
67+
outline: none;
6868
}

src/assets/styles/_theme.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@
1313
--theme-scrollbar-thumb: color-mix(in srgb, var(--theme-base) 20%, var(--theme-bg) 80%);
1414
--text-muted: color-mix(in srgb, var(--theme-base) 20%, var(--theme-bg) 80%);
1515
--text-muted-2: color-mix(in srgb, var(--theme-base) 30%, var(--theme-bg) 70%);
16+
--focus-visible-outline-color: color-mix(in srgb, var(--theme-base) 50%, var(--theme-bg));
17+
--focus-visible-outline: var(--focus-visible-outline-color) auto 1px;
1618
}

src/assets/styles/components/_all.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@
88
@use "switch";
99
@use "toggle-form-area";
1010
@use "message";
11+
@use "external-link";
12+
@use "prompt-input";
Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
.api-info {
22
font-size: 0.85rem;
3-
color: var(--text-dark);
4-
opacity: 0.7;
5-
margin-bottom: 0.5rem;
3+
color: hsl(from var(--brand-info) h s calc(l + 5));
4+
margin-block: 0.5rem;
5+
background-color: rgb(from var(--theme-base) r g b / 3.5%);
6+
display: flex;
7+
text-align: left;
8+
border-radius: 6px;
9+
padding: 0.75rem 1rem;
10+
11+
.icon {
12+
font-size: 1.25rem;
13+
display: block;
14+
margin-right: 0.75rem;
15+
}
616
}

src/assets/styles/components/_base-input.scss

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
display: flex;
33
gap: 0.5rem;
44
flex-direction: column;
5-
overflow: auto;
5+
// overflow: auto;
66
text-align: left;
77

88
label {
@@ -32,6 +32,10 @@
3232
font-size: 0.9rem;
3333
color: var(--text-dark);
3434
overflow: hidden;
35+
36+
&:focus-visible {
37+
outline: var(--focus-visible-outline);
38+
}
3539
}
3640
}
3741

@@ -94,6 +98,10 @@
9498
&[aria-checked="true"] .slider:before {
9599
transform: translateX(1em);
96100
}
101+
102+
&:focus-visible {
103+
outline: var(--focus-visible-outline);
104+
}
97105
}
98106

99107
.slider {

src/assets/styles/components/_buttons.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ $btn-border-radius: 8px;
8484
&:hover .title-popup {
8585
animation: fadeInAfterDelay 0.8s forwards;
8686
}
87+
88+
>.material-symbols-outlined {
89+
font-size: 1.5em;
90+
margin-right: 0.25rem;
91+
}
8792
}
8893

8994
@keyframes fadeInAfterDelay {

src/assets/styles/components/_dropdown.scss

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
.dropdown-trigger {
66
cursor: pointer;
7+
8+
&:focus-visible {
9+
outline: var(--focus-visible-outline);
10+
}
711
}
812

913
.dropdown-popover {
@@ -42,7 +46,7 @@
4246
font-size: 0.8rem;
4347
}
4448

45-
&:hover:not(.disabled) {
49+
&:hover:not(.disabled), &:focus-visible {
4650
background-color: rgb(from var(--theme-base) r g b / 5%);
4751
}
4852

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.external-link {
2+
&:focus-visible {
3+
outline: var(--focus-visible-outline);
4+
}
5+
}

0 commit comments

Comments
 (0)