Skip to content

Commit a4b37bf

Browse files
Merge pull request #120 from iamsrikanthnani/release/v0.1.7
Release/v0.1.7
2 parents 6bdf2f3 + 49b9110 commit a4b37bf

13 files changed

Lines changed: 119 additions & 20 deletions

File tree

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "pluely",
33
"private": false,
4-
"version": "0.1.6",
4+
"version": "0.1.7",
55
"description": "The Open Source Alternative to Cluely - A lightning-fast, privacy-first AI assistant that works seamlessly during meetings, interviews, and conversations without anyone knowing.",
66
"author": {
77
"name": "Srikanth Nani",

src-tauri/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pluely"
3-
version = "0.1.6"
3+
version = "0.1.7"
44
description = "The Open Source Alternative to Cluely - A lightning-fast, privacy-first AI assistant that works seamlessly during meetings, interviews, and conversations without anyone knowing."
55
authors = ["Srikanth Nani <srikanthnani1202@gmail.com>"]
66
license = "GPL-3.0"

src-tauri/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://schema.tauri.app/config/2",
33
"productName": "Pluely",
4-
"version": "0.1.6",
4+
"version": "0.1.7",
55
"identifier": "com.srikanthnani.pluely",
66
"build": {
77
"beforeDevCommand": "npm run dev",

src/App.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ import {
1111
StatusIndicator,
1212
} from "@/components";
1313
import { useApp } from "@/hooks";
14-
14+
import { useApp as useAppContext } from "@/contexts";
1515
const App = () => {
1616
const {
1717
isHidden,
1818
systemAudio,
1919
handleSelectConversation,
2020
handleNewConversation,
2121
} = useApp();
22+
const { customizable } = useAppContext();
2223
return (
2324
<div
2425
className={`w-screen h-screen flex overflow-hidden justify-center items-start ${
@@ -66,7 +67,7 @@ const App = () => {
6667
<Updater />
6768
<DragButton />
6869
</Card>
69-
<CustomCursor />
70+
{customizable.cursor.type === "invisible" ? <CustomCursor /> : null}
7071
</div>
7172
);
7273
};

src/components/settings/Cursor.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import {
2+
Header,
3+
Select,
4+
SelectContent,
5+
SelectItem,
6+
SelectTrigger,
7+
SelectValue,
8+
} from "@/components";
9+
import { useApp } from "@/contexts";
10+
import { CursorType } from "@/lib/storage";
11+
import { MousePointer, MousePointer2, Pointer, TextCursor } from "lucide-react";
12+
13+
interface CursorSelectionProps {
14+
className?: string;
15+
}
16+
17+
export const CursorSelection = ({ className }: CursorSelectionProps) => {
18+
const { customizable, setCursorType } = useApp();
19+
20+
return (
21+
<div id="cursor" className={`space-y-2 ${className}`}>
22+
<Header
23+
title="Cursor"
24+
description="Control pluely cursor visibility"
25+
isMainTitle
26+
rightSlot={
27+
<Select
28+
value={customizable.cursor.type}
29+
onValueChange={(value) => setCursorType(value as CursorType)}
30+
>
31+
<SelectTrigger>
32+
<SelectValue placeholder="Select a cursor type" />
33+
</SelectTrigger>
34+
<SelectContent position="popper" align="end">
35+
<SelectItem value="invisible">
36+
Invisible (<MousePointer2 className="size-3 px-0" />)
37+
</SelectItem>
38+
<SelectItem value="default">
39+
Default (<MousePointer className="size-3" />)
40+
</SelectItem>
41+
<SelectItem value="auto">
42+
Auto (
43+
<MousePointer className="size-3" />/
44+
<TextCursor className="size-3" /> /
45+
<Pointer className="size-3" />)
46+
</SelectItem>
47+
</SelectContent>
48+
</Select>
49+
}
50+
/>
51+
</div>
52+
);
53+
};

src/components/settings/SettingsNavigation.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const SETTINGS_SECTIONS = [
66
{ id: "theme", label: "Theme" },
77
{ id: "screenshot", label: "Screenshot config" },
88
{ id: "shortcuts", label: "Shortcuts" },
9+
{ id: "cursor", label: "Cursor" },
910
{ id: "audio", label: "Audio devices" },
1011
{ id: "autostart", label: "App startup" },
1112
{ id: "app-icon", label: "App icon" },
@@ -38,7 +39,7 @@ export const SettingsNavigation = () => {
3839
size="sm"
3940
variant="outline"
4041
onClick={() => scrollToSection(section.id)}
41-
className="h-fit px-2.5 py-1"
42+
className="h-fit px-2 py-1"
4243
title={`Jump to ${section.label} section`}
4344
>
4445
<span className="text-[10px]">{section.label}</span>

src/components/settings/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { PluelyApiSetup } from "./PluelyApiSetup";
2222
import { ShortcutManager } from "./shortcuts";
2323
import Theme from "./Theme";
2424
import { SettingsNavigation } from "./SettingsNavigation";
25+
import { CursorSelection } from "./Cursor";
2526

2627
export const Settings = () => {
2728
const settings = useSettings();
@@ -66,6 +67,9 @@ export const Settings = () => {
6667
{/* Screenshot Configs */}
6768
<ScreenshotConfigs {...settings} />
6869

70+
{/* Cursor Selection */}
71+
<CursorSelection />
72+
6973
{/* Keyboard Shortcuts */}
7074
<ShortcutManager />
7175

src/contexts/app.context.tsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import {
1313
updateTitlesVisibility,
1414
updateAutostart,
1515
CustomizableState,
16+
DEFAULT_CUSTOMIZABLE_STATE,
17+
CursorType,
18+
updateCursorType,
1619
} from "@/lib/storage";
1720
import { IContextType, ScreenshotConfig, TYPE_PROVIDER } from "@/types";
1821
import curl2Json from "@bany/curl-to-json";
@@ -113,12 +116,9 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
113116
});
114117

115118
// Unified Customizable State
116-
const [customizable, setCustomizable] = useState<CustomizableState>({
117-
appIcon: { isVisible: true },
118-
alwaysOnTop: { isEnabled: true },
119-
titles: { isEnabled: true },
120-
autostart: { isEnabled: true },
121-
});
119+
const [customizable, setCustomizable] = useState<CustomizableState>(
120+
DEFAULT_CUSTOMIZABLE_STATE
121+
);
122122
const [hasActiveLicense, setHasActiveLicense] = useState<boolean>(false);
123123

124124
// Pluely API State
@@ -213,6 +213,8 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
213213
const customizableState = getCustomizableState();
214214
setCustomizable(customizableState);
215215

216+
updateCursor(customizableState.cursor.type || "invisible");
217+
216218
const stored = safeLocalStorage.getItem(STORAGE_KEYS.CUSTOMIZABLE);
217219
if (!stored) {
218220
// save the default state
@@ -224,6 +226,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
224226
if (!parsed.autostart) {
225227
// save the merged state with new autostart property
226228
setCustomizableState(customizableState);
229+
updateCursor(customizableState.cursor.type || "invisible");
227230
}
228231
} catch (error) {
229232
console.debug("Failed to check customizable state schema:", error);
@@ -239,6 +242,16 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
239242
}
240243
};
241244

245+
const updateCursor = (type: CursorType | undefined) => {
246+
try {
247+
const safeType = type || "invisible";
248+
const cursorValue = type === "invisible" ? "none" : safeType;
249+
document.documentElement.style.setProperty("--cursor-type", cursorValue);
250+
} catch (error) {
251+
document.documentElement.style.setProperty("--cursor-type", "none");
252+
}
253+
};
254+
242255
// Load data on mount
243256
useEffect(() => {
244257
const initializeApp = async () => {
@@ -470,6 +483,13 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
470483
}
471484
};
472485

486+
const setCursorType = (type: CursorType) => {
487+
setCustomizable((prev) => ({ ...prev, cursor: { type } }));
488+
updateCursor(type);
489+
updateCursorType(type);
490+
loadData();
491+
};
492+
473493
const setPluelyApiEnabled = (enabled: boolean) => {
474494
setPluelyApiEnabledState(enabled);
475495
safeLocalStorage.setItem(STORAGE_KEYS.PLUELY_API_ENABLED, String(enabled));
@@ -503,6 +523,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
503523
getActiveLicenseStatus,
504524
selectedAudioDevices,
505525
setSelectedAudioDevices,
526+
setCursorType,
506527
};
507528

508529
return <AppContext.Provider value={value}>{children}</AppContext.Provider>;

0 commit comments

Comments
 (0)