From 31e7db1fa135eeca907fbae525a662ba214faf37 Mon Sep 17 00:00:00 2001 From: afnx Date: Sun, 26 Oct 2025 22:12:21 -0700 Subject: [PATCH 1/7] feat: update dependencies and add new packages for improved functionality --- package-lock.json | 52 +++++++++++++++++++++++++++++++++++------------ package.json | 4 +++- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 072727b..d7a2524 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,13 +9,14 @@ "version": "0.0.1", "dependencies": { "@expo/vector-icons": "^15.0.2", + "@react-native-community/blur": "^4.4.1", "@react-navigation/bottom-tabs": "^7.4.0", "@react-navigation/elements": "^2.6.3", "@react-navigation/native": "^7.1.8", "@reduxjs/toolkit": "^2.9.0", "expo": "~54.0.13", "expo-constants": "~18.0.9", - "expo-dev-client": "~6.0.15", + "expo-dev-client": "~6.0.16", "expo-font": "~14.0.9", "expo-haptics": "~15.0.7", "expo-image": "~3.0.9", @@ -30,6 +31,7 @@ "react-dom": "19.1.0", "react-native": "0.81.4", "react-native-gesture-handler": "~2.28.0", + "react-native-keyboard-controller": "^1.19.2", "react-native-reanimated": "~4.1.1", "react-native-safe-area-context": "~5.6.0", "react-native-screens": "~4.16.0", @@ -3243,6 +3245,16 @@ "react-native": "^0.0.0-0 || >=0.65 <1.0" } }, + "node_modules/@react-native-community/blur": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@react-native-community/blur/-/blur-4.4.1.tgz", + "integrity": "sha512-XBSsRiYxE/MOEln2ayunShfJtWztHwUxLFcSL20o+HNNRnuUDv+GXkF6FmM2zE8ZUfrnhQ/zeTqvnuDPGw6O8A==", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/@react-native/assets-registry": { "version": "0.81.4", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.4.tgz", @@ -7920,13 +7932,13 @@ } }, "node_modules/expo-dev-client": { - "version": "6.0.15", - "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-6.0.15.tgz", - "integrity": "sha512-zdpuK7wPp7q01qE90EDQunL49cumGPEKCGDykB86K0myCPZt1lvkpyy4OHTh3urm3pkikWOb9biuVgLdq7oq/g==", + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-6.0.16.tgz", + "integrity": "sha512-8GLud/dtNteqChL9pNGqLBSHd7of2scFmsgN5WwWgtt2dET7+EJM/K1zp0FYUzfmIF5NLsf5xUDg6AjDldOLqg==", "license": "MIT", "dependencies": { - "expo-dev-launcher": "6.0.15", - "expo-dev-menu": "7.0.14", + "expo-dev-launcher": "6.0.16", + "expo-dev-menu": "7.0.15", "expo-dev-menu-interface": "2.0.0", "expo-manifests": "~1.0.8", "expo-updates-interface": "~2.0.0" @@ -7936,12 +7948,12 @@ } }, "node_modules/expo-dev-launcher": { - "version": "6.0.15", - "resolved": "https://registry.npmjs.org/expo-dev-launcher/-/expo-dev-launcher-6.0.15.tgz", - "integrity": "sha512-aFRKg9qcq47Y/1UGTPhtOWrbI5jOFgttOfhdBu9knLKl72jGXpDTdBHsHPkCfIezzDrSoZccl482Hv7RvKfrqA==", + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/expo-dev-launcher/-/expo-dev-launcher-6.0.16.tgz", + "integrity": "sha512-OVg5T5ip7evh8zHJeIj2IYgtvTeY8EOiwNQYlmN0JHAw8wlUxYHnSf08RcevVgYTKcIryCyeLG5UHxsQQWbycA==", "license": "MIT", "dependencies": { - "expo-dev-menu": "7.0.14", + "expo-dev-menu": "7.0.15", "expo-manifests": "~1.0.8" }, "peerDependencies": { @@ -7949,9 +7961,9 @@ } }, "node_modules/expo-dev-menu": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/expo-dev-menu/-/expo-dev-menu-7.0.14.tgz", - "integrity": "sha512-nWyzSztFWfnhDOiKJ6DuZLjIbq+tG9e5y4TDmW6wYlSKKPBXbdOn2UdxaknhSqZrw6NwWMcjyhS+QG4MoDGD8w==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/expo-dev-menu/-/expo-dev-menu-7.0.15.tgz", + "integrity": "sha512-aThUhoBUuQVbCS2k0MwP28/au46FqOXAAiGtCYIWp+Hne95RgFO+KaO0VGksJFwK7I9IPbbminm8ijZDf2KzXg==", "license": "MIT", "dependencies": { "expo-dev-menu-interface": "2.0.0" @@ -13805,6 +13817,20 @@ "react-native": "*" } }, + "node_modules/react-native-keyboard-controller": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/react-native-keyboard-controller/-/react-native-keyboard-controller-1.19.2.tgz", + "integrity": "sha512-121W+WLnYMTpVyAwm2tPjBc6NLKS2srQOvlkFMYZEYNIsZPvWLQ92n7kBlR32Wpsm8t9rE9xfWZEyNPhCoe+mQ==", + "license": "MIT", + "dependencies": { + "react-native-is-edge-to-edge": "^1.2.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*", + "react-native-reanimated": ">=3.0.0" + } + }, "node_modules/react-native-reanimated": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.3.tgz", diff --git a/package.json b/package.json index f9a52f0..902c79d 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,14 @@ }, "dependencies": { "@expo/vector-icons": "^15.0.2", + "@react-native-community/blur": "^4.4.1", "@react-navigation/bottom-tabs": "^7.4.0", "@react-navigation/elements": "^2.6.3", "@react-navigation/native": "^7.1.8", "@reduxjs/toolkit": "^2.9.0", "expo": "~54.0.13", "expo-constants": "~18.0.9", - "expo-dev-client": "~6.0.15", + "expo-dev-client": "~6.0.16", "expo-font": "~14.0.9", "expo-haptics": "~15.0.7", "expo-image": "~3.0.9", @@ -34,6 +35,7 @@ "react-dom": "19.1.0", "react-native": "0.81.4", "react-native-gesture-handler": "~2.28.0", + "react-native-keyboard-controller": "^1.19.2", "react-native-reanimated": "~4.1.1", "react-native-safe-area-context": "~5.6.0", "react-native-screens": "~4.16.0", From be27e02a76ffcc1c76048a858cae025ae5b3a3f5 Mon Sep 17 00:00:00 2001 From: afnx Date: Sun, 26 Oct 2025 22:12:34 -0700 Subject: [PATCH 2/7] feat: add IconButton component and extend Icons with new icon constants --- src/components/IconButton.tsx | 57 +++++++++++++++++++++++++++++++++++ src/constants/Icons.ts | 7 +++-- 2 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/components/IconButton.tsx diff --git a/src/components/IconButton.tsx b/src/components/IconButton.tsx new file mode 100644 index 0000000..1132f81 --- /dev/null +++ b/src/components/IconButton.tsx @@ -0,0 +1,57 @@ +import { Icon, IconSizes } from "@/src/constants/Icons"; +import { Ionicons } from "@expo/vector-icons"; +import { ColorValue, Pressable, StyleSheet, ViewStyle } from "react-native"; + +interface IconButtonProps { + icon: Icon; + size?: number; + color?: ColorValue; + disabled?: boolean; + accessibilityLabel?: string; + style?: ViewStyle; + onPress?: () => void; +} + +export default function IconButton({ + icon, + size = IconSizes.medium, + color = "#000", + disabled = false, + accessibilityLabel, + style, + onPress, +}: IconButtonProps) { + return ( + [ + styles.button, + style, + disabled && styles.disabled, + pressed && !disabled && styles.pressed, + ]} + onPress={onPress} + disabled={disabled} + accessibilityRole="button" + accessibilityLabel={accessibilityLabel} + > + + + ); +} + +const styles = StyleSheet.create({ + button: { + padding: 8, + borderRadius: 20, + alignItems: "center", + justifyContent: "center", + }, + disabled: { + opacity: 0.4, + }, + pressed: { + opacity: 0.7, + }, +}); + +export { IconSizes }; diff --git a/src/constants/Icons.ts b/src/constants/Icons.ts index 9799262..c6260c6 100644 --- a/src/constants/Icons.ts +++ b/src/constants/Icons.ts @@ -27,6 +27,9 @@ export const Icons = { secure: "lock-closed" as const, insecure: "warning" as const, search: "search" as const, + microphone: "mic-outline" as const, + deleteInput: "close-circle" as const, + readerOutline: "reader-outline" as const, // Tab management closeTab: "close" as const, @@ -54,8 +57,8 @@ export const Icons = { textSize: "text" as const, // Bookmarks and favorites - bookmark: "bookmark-outline" as const, - bookmarkFilled: "bookmark" as const, + bookmark: "book-outline" as const, + bookmarkFilled: "book" as const, star: "star-outline" as const, starFilled: "star" as const, From 51eeb7296ba786b82719ec496d71c3b6fb0b2692 Mon Sep 17 00:00:00 2001 From: afnx Date: Sun, 26 Oct 2025 22:12:42 -0700 Subject: [PATCH 3/7] refactor: comment out pathname and search appending logic in formatUrlForDisplay function --- src/features/browser/utils/urlUtils.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/features/browser/utils/urlUtils.ts b/src/features/browser/utils/urlUtils.ts index b22f256..9e26511 100644 --- a/src/features/browser/utils/urlUtils.ts +++ b/src/features/browser/utils/urlUtils.ts @@ -105,13 +105,13 @@ export const formatUrlForDisplay = (url: string): string => { const urlObj = new URL(url); let displayUrl = urlObj.hostname; - if (urlObj.pathname !== "/") { - displayUrl += urlObj.pathname; - } + // if (urlObj.pathname !== "/") { + // displayUrl += urlObj.pathname; + // } - if (urlObj.search) { - displayUrl += urlObj.search; - } + // if (urlObj.search) { + // displayUrl += urlObj.search; + // } return displayUrl; } catch { From f26b7123bea5b927b4f72a163489c92c5a9e8dcc Mon Sep 17 00:00:00 2001 From: afnx Date: Sun, 26 Oct 2025 22:12:54 -0700 Subject: [PATCH 4/7] feat: add AddressBar and AddressBarDisplay components for improved browser navigation --- .../screens/BrowserScreen/AddressBar.tsx | 128 ++++++++++++++++++ .../BrowserScreen/AddressBarDisplay.tsx | 36 +++++ 2 files changed, 164 insertions(+) create mode 100644 src/features/browser/screens/BrowserScreen/AddressBar.tsx create mode 100644 src/features/browser/screens/BrowserScreen/AddressBarDisplay.tsx diff --git a/src/features/browser/screens/BrowserScreen/AddressBar.tsx b/src/features/browser/screens/BrowserScreen/AddressBar.tsx new file mode 100644 index 0000000..d3ebde0 --- /dev/null +++ b/src/features/browser/screens/BrowserScreen/AddressBar.tsx @@ -0,0 +1,128 @@ +import IconButton from "@/src/components/IconButton"; +import { Icons } from "@/src/constants/Icons"; +import { useTheme } from "@/src/theme/useTheme"; +import { useEffect, useState } from "react"; +import { StyleSheet, TextInput, View } from "react-native"; +import { useBrowser } from "../../hooks/useBrowser"; +import { formatUrlForDisplay } from "../../utils/urlUtils"; + +interface AddressBarProps { + onFocusChange?: (isFocused: boolean) => void; +} + +export default function AddressBar({ onFocusChange }: AddressBarProps) { + const theme = useTheme(); + const { activeTab, navigateTab, activeTabId } = useBrowser(); + + const [input, setInput] = useState(activeTab?.url ?? ""); + const [isFocused, setIsFocused] = useState(false); + + const showDeleteIcon = isFocused && input.length > 0; + + // Update input field when active tab changes + useEffect(() => { + setInput(activeTab?.url ?? ""); + }, [activeTab?.url]); + + const handleSubmitEditing = () => { + if (!activeTabId) return; + navigateTab(activeTabId, input); + }; + + const handleFocus = () => { + setIsFocused(true); + onFocusChange?.(true); + }; + + const handleBlur = () => { + setIsFocused(false); + onFocusChange?.(false); + }; + + return ( + + {!isFocused && ( + + + + )} + + + { + if (activeTabId && activeTab?.url) { + navigateTab(activeTabId, activeTab.url); + } + }} + /> + {showDeleteIcon && ( + setInput("")} + /> + )} + + + ); +} + +const styles = StyleSheet.create({ + container: { + flexDirection: "row", + alignItems: "center", + paddingHorizontal: 8, + paddingVertical: 2, + borderRadius: 12, + marginTop: 10, + marginBottom: 16, + marginHorizontal: 32, + }, + input: { + flex: 1, + fontSize: 16, + paddingLeft: 6, + borderRadius: 6, + backgroundColor: "transparent", + textAlign: "center", + }, + iconLeft: { + marginRight: 4, + }, + iconRight: { + marginLeft: 2, + flexDirection: "row", + alignItems: "center", + }, +}); diff --git a/src/features/browser/screens/BrowserScreen/AddressBarDisplay.tsx b/src/features/browser/screens/BrowserScreen/AddressBarDisplay.tsx new file mode 100644 index 0000000..b02bea7 --- /dev/null +++ b/src/features/browser/screens/BrowserScreen/AddressBarDisplay.tsx @@ -0,0 +1,36 @@ +import { useTheme } from "@/src/theme/useTheme"; +import { StyleSheet, Text, View } from "react-native"; +import { useBrowser } from "../../hooks/useBrowser"; +import { formatUrlForDisplay } from "../../utils/urlUtils"; +export default function AddressBarDisplay() { + const theme = useTheme(); + const { activeTab } = useBrowser(); + const { url } = activeTab || {}; + + return ( + + + {formatUrlForDisplay(url || "about:blank")} + + + ); +} + +const styles = StyleSheet.create({ + container: { + justifyContent: "center", + alignItems: "center", + backgroundColor: "transparent", + width: "100%", + paddingTop: 2, + paddingBottom: 8, + paddingHorizontal: 16, + borderTopWidth: StyleSheet.hairlineWidth, + borderTopColor: "#909090", + }, + text: { + color: "#2c3e50", + }, +}); From 493058d797caef3d98d5ad10db01bc7590f0b3e7 Mon Sep 17 00:00:00 2001 From: afnx Date: Sun, 26 Oct 2025 22:13:08 -0700 Subject: [PATCH 5/7] feat: add Toolbar and WebViewComponent --- .../browser/screens/BrowserScreen/Toolbar.tsx | 88 +++++++++++++++++++ .../BrowserScreen/WebViewComponent.tsx | 65 ++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/features/browser/screens/BrowserScreen/Toolbar.tsx create mode 100644 src/features/browser/screens/BrowserScreen/WebViewComponent.tsx diff --git a/src/features/browser/screens/BrowserScreen/Toolbar.tsx b/src/features/browser/screens/BrowserScreen/Toolbar.tsx new file mode 100644 index 0000000..ffbb65b --- /dev/null +++ b/src/features/browser/screens/BrowserScreen/Toolbar.tsx @@ -0,0 +1,88 @@ +import IconButton from "@/src/components/IconButton"; +import { Icons } from "@/src/constants/Icons"; +import { useTheme } from "@/src/theme/useTheme"; +import React from "react"; +import { StyleSheet } from "react-native"; +import { SafeAreaView } from "react-native-safe-area-context"; +import { useBrowser } from "../../hooks/useBrowser"; + +export default function Toolbar() { + const theme = useTheme(); + const { + activeTab, + createNewTab, + closeTabById, + toggleTabs, + toggleBookmark, + isBookmarked, + } = useBrowser(); + + return ( + + { + // WebView navigation logic will go here + }} + /> + { + // WebView navigation logic will go here + }} + /> + { + // More actions (settings, share, etc.) + }} + /> + { + if (activeTab?.url) toggleBookmark(activeTab.url); + }} + /> + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flexDirection: "row", + alignItems: "center", + justifyContent: "space-around", + paddingBottom: 6, + backgroundColor: "transparent", + }, +}); diff --git a/src/features/browser/screens/BrowserScreen/WebViewComponent.tsx b/src/features/browser/screens/BrowserScreen/WebViewComponent.tsx new file mode 100644 index 0000000..406eeb3 --- /dev/null +++ b/src/features/browser/screens/BrowserScreen/WebViewComponent.tsx @@ -0,0 +1,65 @@ +import { useRef } from "react"; +import { StyleSheet, View, ViewProps } from "react-native"; +import { WebView } from "react-native-webview"; +import { useBrowser } from "../../hooks/useBrowser"; + +type WebViewComponentProps = { + bottomPadding?: number; + onScrollDirectionChange?: (direction: "up" | "down") => void; +} & ViewProps; + +const SCROLL_DIRECTION_THRESHOLD = 8; + +export default function WebViewComponent({ + bottomPadding = 0, + style, + onScrollDirectionChange, + ...props +}: WebViewComponentProps) { + const { activeTab, updateTabById } = useBrowser(); + const { url } = activeTab || {}; + // Inject CSS to add bottom padding to the body + const injectedCSS = ` + const style = document.createElement('style'); + style.innerHTML = 'body { padding-bottom: ${bottomPadding}px !important; box-sizing: border-box; }'; + document.head.appendChild(style); + `; + + const lastScrollY = useRef(0); + const lastDirection = useRef<"up" | "down" | null>(null); // pixels + const handleScroll = (event: any) => { + const currentY = event.nativeEvent.contentOffset?.y ?? 0; + const diff = currentY - lastScrollY.current; + + if (Math.abs(diff) > SCROLL_DIRECTION_THRESHOLD) { + const newDirection = diff > 0 ? "down" : "up"; + if (newDirection !== lastDirection.current) { + onScrollDirectionChange?.(newDirection); + lastDirection.current = newDirection; + } + } + lastScrollY.current = currentY; + }; + + return ( + + { + if (activeTab?.id) { + updateTabById(activeTab!.id, { url: navState.url }); + } + }} + onScroll={handleScroll} + /> + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#ecf0f1", + }, +}); From 0a8f55ac70c1ba423aa456d81a82742944b4cf93 Mon Sep 17 00:00:00 2001 From: afnx Date: Sun, 26 Oct 2025 22:13:15 -0700 Subject: [PATCH 6/7] feat: implement BrowserScreen with AddressBar, Toolbar, and WebViewComponent --- .../browser/screens/BrowserScreen/index.tsx | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/features/browser/screens/BrowserScreen/index.tsx diff --git a/src/features/browser/screens/BrowserScreen/index.tsx b/src/features/browser/screens/BrowserScreen/index.tsx new file mode 100644 index 0000000..d3fc774 --- /dev/null +++ b/src/features/browser/screens/BrowserScreen/index.tsx @@ -0,0 +1,136 @@ +import { useTheme } from "@/src/theme/useTheme"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { Animated, StyleSheet, View } from "react-native"; +import { + KeyboardEvents, + useKeyboardAnimation, +} from "react-native-keyboard-controller"; +import { SafeAreaView } from "react-native-safe-area-context"; +import { useBrowser } from "../../hooks/useBrowser"; +import AddressBar from "./AddressBar"; +import AddressBarDisplay from "./AddressBarDisplay"; +import Toolbar from "./Toolbar"; +import WebViewComponent from "./WebViewComponent"; + +const KEYBOARD_OPENED_HEIGHT = 102; +const KEYBOARD_CLOSED_HEIGHT = 0; + +export default function BrowserScreen() { + const theme = useTheme(); + const { showTabs } = useBrowser(); + const { height, progress } = useKeyboardAnimation(); + + const [isAddressBarFocused, setAddressBarFocused] = useState(false); + const [isKeyboardVisible, setKeyboardVisible] = useState(false); + + const [scrollDirection, setScrollDirection] = useState<"up" | "down" | null>( + null + ); + + const showAddressBar = !isKeyboardVisible || isAddressBarFocused; + const showBottomContainer = scrollDirection !== "down"; + + useEffect(() => { + const show = KeyboardEvents.addListener("keyboardWillShow", (e) => { + setKeyboardVisible(true); + }); + + const hide = KeyboardEvents.addListener("keyboardWillHide", (e) => { + setKeyboardVisible(false); + }); + + return () => { + show.remove(); + hide.remove(); + }; + }, []); + + const onAddressBarFocusChange = useCallback((isFocused: boolean) => { + setAddressBarFocused(isFocused); + setKeyboardVisible(false); + }, []); + + const offset = progress.interpolate({ + inputRange: [0, 1], + outputRange: [KEYBOARD_CLOSED_HEIGHT, KEYBOARD_OPENED_HEIGHT], + }); + + const addressBarStyle = useMemo( + () => [ + { + transform: [ + { + translateY: Animated.add(height, offset), + }, + ], + }, + { backgroundColor: "white" }, + ], + [height, offset] + ); + + const bottomContainerY = useMemo(() => new Animated.Value(0), []); + + useEffect(() => { + Animated.timing(bottomContainerY, { + toValue: showBottomContainer ? 0 : 200, + duration: 400, + useNativeDriver: true, + }).start(); + }, [showBottomContainer, bottomContainerY]); + + return ( + + + + + + + + + + {showAddressBar && ( + + )} + {!showAddressBar && } + + {/* Toolbar contains the SafeAreaView */} + + + + ); +} + +const styles = StyleSheet.create({ + topContainer: { + flex: 1, + }, + webViewContainer: { + flex: 1, + backgroundColor: "transparent", + }, + bottomContainer: { + width: "100%", + }, +}); From 6128469e9dc1331a2482ee8ce2658a86e9002a87 Mon Sep 17 00:00:00 2001 From: afnx Date: Sun, 26 Oct 2025 22:13:25 -0700 Subject: [PATCH 7/7] feat: integrate KeyboardProvider in RootLayout and simplify Index component to render BrowserScreen --- src/app/_layout.tsx | 5 +++- src/app/index.tsx | 58 ++------------------------------------------- 2 files changed, 6 insertions(+), 57 deletions(-) diff --git a/src/app/_layout.tsx b/src/app/_layout.tsx index f8105be..f4296c8 100644 --- a/src/app/_layout.tsx +++ b/src/app/_layout.tsx @@ -4,6 +4,7 @@ import { Stack } from "expo-router"; import { StatusBar } from "expo-status-bar"; import React from "react"; import { ActivityIndicator, Text, View } from "react-native"; +import { KeyboardProvider } from "react-native-keyboard-controller"; import { SafeAreaProvider } from "react-native-safe-area-context"; import { Provider } from "react-redux"; import { PersistGate } from "redux-persist/integration/react"; @@ -40,7 +41,9 @@ export default function RootLayout() { } persistor={persistor}> - + + + diff --git a/src/app/index.tsx b/src/app/index.tsx index 9bcf09d..1403f22 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -1,59 +1,5 @@ -import { useSettings } from "@/src/features/settings/hooks/useSettings"; -import { useTheme } from "@/src/theme/useTheme"; -import { Pressable, Text, View } from "react-native"; +import BrowserScreen from "@/src/features/browser/screens/BrowserScreen"; export default function Index() { - const theme = useTheme(); - const settings = useSettings(); - - return ( - - - The current theme color is {theme.name}.{"\n"} - The current theme mode is {settings.theme}. - - settings.switchTheme("system")}> - - System Theme - - - settings.switchTheme("light")}> - - Light Theme - - - settings.switchTheme("dark")}> - - Dark Theme - - - - ); + return ; }