Skip to content

Commit 781a411

Browse files
committed
feat: implement System Preferences app with settings for appearance, connectivity, and hardware controls
1 parent 7d4efd2 commit 781a411

1 file changed

Lines changed: 126 additions & 6 deletions

File tree

src/components/apps/SystemPreferences.tsx

Lines changed: 126 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ const categories = [
1010
icon: "i-charm:bluetooth",
1111
color: "bg-blue-500"
1212
},
13+
{
14+
id: "airdrop",
15+
title: "AirDrop",
16+
icon: "i-material-symbols:rss-feed-rounded",
17+
color: "bg-blue-500"
18+
},
19+
{ id: "general", title: "General", icon: "i-bi:gear-fill", color: "bg-gray-500" },
1320
{
1421
id: "appearance",
1522
title: "Appearance",
@@ -23,27 +30,36 @@ const categories = [
2330
color: "bg-gray-500"
2431
},
2532
{ id: "displays", title: "Displays", icon: "i-bi:display", color: "bg-blue-500" },
26-
{ id: "sound", title: "Sound", icon: "i-bi:volume-up-fill", color: "bg-orange-500" }
33+
{ id: "sound", title: "Sound", icon: "i-bi:volume-up-fill", color: "bg-orange-500" },
34+
{ id: "battery", title: "Battery", icon: "i-bi:battery-half", color: "bg-green-500" },
35+
{
36+
id: "privacy",
37+
title: "Privacy & Security",
38+
icon: "i-bi:shield-lock-fill",
39+
color: "bg-blue-500"
40+
}
2741
];
2842

2943
export default function SystemPreferences() {
3044
const [activeTab, setActiveTab] = useState("appearance");
45+
const batteryState = useBattery();
3146

32-
const { dark, wifi, bluetooth, volume, brightness, dockSize, dockMag } = useStore(
33-
(state: any) => ({
47+
const { dark, wifi, bluetooth, airdrop, volume, brightness, dockSize, dockMag } =
48+
useStore((state: any) => ({
3449
dark: state.dark,
3550
wifi: state.wifi,
3651
bluetooth: state.bluetooth,
52+
airdrop: state.airdrop,
3753
volume: state.volume,
3854
brightness: state.brightness,
3955
dockSize: state.dockSize,
4056
dockMag: state.dockMag
41-
})
42-
);
57+
}));
4358

4459
const {
4560
toggleWIFI,
4661
toggleBluetooth,
62+
toggleAirdrop,
4763
toggleDark,
4864
toggleFullScreen,
4965
setVolume,
@@ -53,6 +69,7 @@ export default function SystemPreferences() {
5369
} = useStore((state: any) => ({
5470
toggleWIFI: state.toggleWIFI,
5571
toggleBluetooth: state.toggleBluetooth,
72+
toggleAirdrop: state.toggleAirdrop,
5673
toggleDark: state.toggleDark,
5774
toggleFullScreen: state.toggleFullScreen,
5875
setVolume: state.setVolume,
@@ -206,8 +223,111 @@ export default function SystemPreferences() {
206223
</div>
207224
</div>
208225
);
226+
case "airdrop":
227+
return (
228+
<div className="space-y-6 w-full max-w-md">
229+
<h2 className="text-2xl font-bold mb-4">AirDrop</h2>
230+
<div className="flex items-center justify-between p-4 rounded-lg bg-gray-500/10">
231+
<div className="flex flex-col">
232+
<span className="font-semibold">AirDrop Visibility</span>
233+
<span className="text-xs text-gray-500 dark:text-gray-400">
234+
Allow others to send files to this Mac.
235+
</span>
236+
</div>
237+
<button
238+
onClick={toggleAirdrop}
239+
className={`w-12 h-6 rounded-full transition-colors relative ${airdrop ? "bg-blue-500" : "bg-gray-400"}`}
240+
>
241+
<div
242+
className={`absolute top-1 w-4 h-4 rounded-full bg-white transition-transform ${airdrop ? "translate-x-7" : "translate-x-1"}`}
243+
/>
244+
</button>
245+
</div>
246+
</div>
247+
);
248+
case "general":
249+
return (
250+
<div className="space-y-6 w-full max-w-md">
251+
<h2 className="text-2xl font-bold mb-4">General</h2>
252+
<div className="flex flex-col p-4 rounded-lg bg-gray-500/10 space-y-4">
253+
<div className="flex justify-between items-center pb-3 border-b border-gray-500/30">
254+
<span>About</span>
255+
<span className="i-bi:chevron-right text-c-500" />
256+
</div>
257+
<div className="flex justify-between items-center pb-3 border-b border-gray-500/30">
258+
<span>Software Update</span>
259+
<span className="i-bi:chevron-right text-c-500" />
260+
</div>
261+
<div className="flex justify-between items-center pb-3 border-b border-gray-500/30">
262+
<span>Storage</span>
263+
<span className="i-bi:chevron-right text-c-500" />
264+
</div>
265+
<div className="flex justify-between items-center">
266+
<span>AirDrop & Handoff</span>
267+
<span className="i-bi:chevron-right text-c-500" />
268+
</div>
269+
</div>
270+
</div>
271+
);
272+
case "battery":
273+
return (
274+
<div className="space-y-6 w-full max-w-md">
275+
<h2 className="text-2xl font-bold mb-4">Battery</h2>
276+
<div className="flex flex-col p-6 rounded-lg bg-gray-500/10 space-y-4">
277+
<div className="flex items-center justify-between">
278+
<div className="flex flex-col">
279+
<span className="text-3xl font-bold">
280+
{(batteryState.level * 100).toFixed()}%
281+
</span>
282+
<span
283+
className={`text-sm ${batteryState.charging ? "text-green-600 dark:text-green-400" : "text-gray-600 dark:text-gray-400"}`}
284+
>
285+
{batteryState.charging ? "Charging" : "Running on Battery"}
286+
</span>
287+
</div>
288+
<span
289+
className={`${batteryState.charging ? "i-bi:battery-charging text-green-500" : "i-bi:battery-half text-gray-500"} text-5xl`}
290+
/>
291+
</div>
292+
<div className="h-px bg-gray-500/30 my-2" />
293+
<div className="flex justify-between items-center">
294+
<span>Low Power Mode</span>
295+
<button className="px-3 py-1 bg-gray-200 dark:bg-gray-700 rounded text-sm hover:opacity-80">
296+
Never
297+
</button>
298+
</div>
299+
</div>
300+
</div>
301+
);
302+
case "privacy":
303+
return (
304+
<div className="space-y-6 w-full max-w-md">
305+
<h2 className="text-2xl font-bold mb-4">Privacy & Security</h2>
306+
<div className="flex flex-col bg-gray-500/10 rounded-lg overflow-hidden">
307+
{[
308+
{ title: "Location Services", status: "On" },
309+
{ title: "Contacts", status: "2 Apps" },
310+
{ title: "Calendars", status: "0 Apps" },
311+
{ title: "Photos", status: "4 Apps" },
312+
{ title: "Microphone", status: "1 App" },
313+
{ title: "Camera", status: "2 Apps" }
314+
].map((item, i) => (
315+
<div
316+
key={item.title}
317+
className={`flex justify-between p-3 ${i !== 5 ? "border-b border-gray-500/30" : ""}`}
318+
>
319+
<span>{item.title}</span>
320+
<div className="flex items-center text-gray-500 dark:text-gray-400 space-x-2">
321+
<span className="text-sm">{item.status}</span>
322+
<span className="i-bi:chevron-right" />
323+
</div>
324+
</div>
325+
))}
326+
</div>
327+
</div>
328+
);
209329
default:
210-
return <div>Select a category</div>;
330+
return <div className="text-gray-500 mt-10">Select a category</div>;
211331
}
212332
};
213333

0 commit comments

Comments
 (0)