Skip to content

Commit 32dc356

Browse files
committed
create v0.12.2 onboarding screen (what's new)
1 parent 6e4ebb4 commit 32dc356

6 files changed

Lines changed: 321 additions & 164 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// Copyright 2025, Command Line Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
export const CurrentOnboardingVersion = "v0.12.1";
4+
export const CurrentOnboardingVersion = "v0.12.2";

frontend/app/onboarding/onboarding-features.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import { TabRpcClient } from "@/app/store/wshrpcutil";
1212
import { isMacOS } from "@/util/platformutil";
1313
import { useEffect, useState } from "react";
1414
import { FakeChat } from "./fakechat";
15-
import { CurrentOnboardingVersion } from "./onboarding-common";
1615
import { EditBashrcCommand, ViewLogoCommand, ViewShortcutsCommand } from "./onboarding-command";
16+
import { CurrentOnboardingVersion } from "./onboarding-common";
1717
import { FakeLayout } from "./onboarding-layout";
1818

1919
type FeaturePageName = "waveai" | "magnify" | "files";
@@ -100,7 +100,7 @@ const WaveAIPage = ({ onNext, onSkip }: { onNext: () => void; onSkip: () => void
100100
<div className="flex flex-col items-start gap-4 text-secondary">
101101
<p>
102102
Wave AI is your terminal assistant with context. I can read your terminal output,
103-
analyze widgets, access files, and help you solve problems faster.
103+
analyze widgets, read/write files, and help you solve problems faster.
104104
</p>
105105

106106
<div className="flex items-start gap-3 w-full">
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// Copyright 2025, Command Line Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import Logo from "@/app/asset/logo.svg";
5+
import { Button } from "@/app/element/button";
6+
import { FlexiModal } from "@/app/modals/modal";
7+
import { CurrentOnboardingVersion } from "@/app/onboarding/onboarding-common";
8+
import { atoms, globalStore } from "@/app/store/global";
9+
import { disableGlobalKeybindings, enableGlobalKeybindings, globalRefocus } from "@/app/store/keymodel";
10+
import { modalsModel } from "@/app/store/modalmodel";
11+
import * as WOS from "@/app/store/wos";
12+
import { RpcApi } from "@/app/store/wshclientapi";
13+
import { TabRpcClient } from "@/app/store/wshrpcutil";
14+
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
15+
import { useEffect, useRef, useState } from "react";
16+
import { debounce } from "throttle-debounce";
17+
import { UpgradeOnboardingModal_v0_12_1_Content } from "./onboarding-upgrade-v0121";
18+
import { UpgradeOnboardingModal_v0_12_2_Content } from "./onboarding-upgrade-v0122";
19+
20+
interface VersionConfig {
21+
version: string;
22+
content: React.ReactNode;
23+
prevText?: string;
24+
nextText?: string;
25+
}
26+
27+
const versions: VersionConfig[] = [
28+
{
29+
version: "v0.12.1",
30+
content: <UpgradeOnboardingModal_v0_12_1_Content />,
31+
nextText: "Next (v0.12.2)",
32+
},
33+
{
34+
version: "v0.12.2",
35+
content: <UpgradeOnboardingModal_v0_12_2_Content />,
36+
prevText: "Prev (v0.12.1)",
37+
},
38+
];
39+
40+
const UpgradeOnboardingPatch = () => {
41+
const modalRef = useRef<HTMLDivElement | null>(null);
42+
const [isCompact, setIsCompact] = useState<boolean>(window.innerHeight < 800);
43+
const [currentIndex, setCurrentIndex] = useState<number>(versions.length - 1);
44+
45+
const currentVersion = versions[currentIndex];
46+
const hasPrev = currentIndex > 0;
47+
const hasNext = currentIndex < versions.length - 1;
48+
49+
const updateModalHeight = () => {
50+
const windowHeight = window.innerHeight;
51+
setIsCompact(windowHeight < 800);
52+
if (modalRef.current) {
53+
const modalHeight = modalRef.current.offsetHeight;
54+
const maxHeight = windowHeight * 0.9;
55+
if (maxHeight < modalHeight) {
56+
modalRef.current.style.height = `${maxHeight}px`;
57+
} else {
58+
modalRef.current.style.height = "auto";
59+
}
60+
}
61+
};
62+
63+
useEffect(() => {
64+
updateModalHeight();
65+
const debouncedUpdateModalHeight = debounce(150, updateModalHeight);
66+
window.addEventListener("resize", debouncedUpdateModalHeight);
67+
return () => {
68+
window.removeEventListener("resize", debouncedUpdateModalHeight);
69+
};
70+
}, []);
71+
72+
useEffect(() => {
73+
disableGlobalKeybindings();
74+
return () => {
75+
enableGlobalKeybindings();
76+
};
77+
}, []);
78+
79+
const handleClose = () => {
80+
const clientId = globalStore.get(atoms.clientId);
81+
RpcApi.SetMetaCommand(TabRpcClient, {
82+
oref: WOS.makeORef("client", clientId),
83+
meta: { "onboarding:lastversion": CurrentOnboardingVersion },
84+
});
85+
globalStore.set(modalsModel.upgradeOnboardingOpen, false);
86+
setTimeout(() => {
87+
globalRefocus();
88+
}, 10);
89+
};
90+
91+
const paddingClass = isCompact ? "!py-3 !px-[30px]" : "!p-[30px]";
92+
93+
const handlePrev = () => {
94+
if (hasPrev) {
95+
setCurrentIndex(currentIndex - 1);
96+
}
97+
};
98+
99+
const handleNext = () => {
100+
if (hasNext) {
101+
setCurrentIndex(currentIndex + 1);
102+
}
103+
};
104+
105+
return (
106+
<FlexiModal className={`w-[650px] rounded-[10px] ${paddingClass} relative overflow-hidden`} ref={modalRef}>
107+
<div className="absolute inset-0 bg-gradient-to-br from-accent/[0.25] via-transparent to-accent/[0.05] pointer-events-none rounded-[10px]" />
108+
<div className="flex flex-col w-full h-full relative z-10">
109+
<div className="flex flex-col h-full">
110+
<header className="flex flex-col gap-2 border-b-0 p-0 mt-1 mb-6 w-full unselectable flex-shrink-0">
111+
<div className="flex justify-center">
112+
<Logo />
113+
</div>
114+
<div className="text-center text-[25px] font-normal text-foreground">
115+
Wave {currentVersion.version} Update
116+
</div>
117+
</header>
118+
<OverlayScrollbarsComponent
119+
className="flex-1 overflow-y-auto min-h-0"
120+
options={{ scrollbars: { autoHide: "never" } }}
121+
>
122+
{currentVersion.content}
123+
</OverlayScrollbarsComponent>
124+
<footer className="unselectable flex-shrink-0 mt-4">
125+
<div className="flex flex-row items-center justify-between w-full">
126+
<div className="flex-1 flex justify-start">
127+
{hasPrev && (
128+
<div className="text-sm text-secondary">
129+
<button
130+
onClick={handlePrev}
131+
className="cursor-pointer hover:text-foreground transition-colors"
132+
>
133+
&lt; {currentVersion.prevText}
134+
</button>
135+
</div>
136+
)}
137+
</div>
138+
<div className="flex flex-row items-center justify-center [&>button]:!px-5 [&>button]:!py-2 [&>button]:text-sm">
139+
<Button className="font-[600]" onClick={handleClose}>
140+
Continue
141+
</Button>
142+
</div>
143+
<div className="flex-1 flex justify-end">
144+
{hasNext && (
145+
<div className="text-sm text-secondary">
146+
<button
147+
onClick={handleNext}
148+
className="cursor-pointer hover:text-foreground transition-colors"
149+
>
150+
{currentVersion.nextText} &gt;
151+
</button>
152+
</div>
153+
)}
154+
</div>
155+
</div>
156+
</footer>
157+
</div>
158+
</div>
159+
</FlexiModal>
160+
);
161+
};
162+
163+
UpgradeOnboardingPatch.displayName = "UpgradeOnboardingPatch";
164+
165+
export { UpgradeOnboardingPatch };

0 commit comments

Comments
 (0)