feat: enhance layout components with iOS version checks and improve header styles

This commit is contained in:
daniel31x13
2026-03-10 14:15:30 -04:00
parent 12608564d7
commit bcd3c73713
7 changed files with 95 additions and 79 deletions

View File

@@ -7,6 +7,8 @@ export default function Layout() {
const router = useRouter();
const { colorScheme } = useColorScheme();
const isIOS26Plus = Platform.OS === "ios" && Number(Platform.Version) >= 26;
return (
<Stack
screenOptions={{
@@ -26,7 +28,7 @@ export default function Layout() {
headerIconColor: colorScheme === "dark" ? "white" : "black",
},
headerLargeTitleStyle: {
color: rawTheme[colorScheme as ThemeName]["base-content"], // or whatever token you want
color: rawTheme[colorScheme as ThemeName]["base-content"],
},
headerTitleStyle: {
color: rawTheme[colorScheme as ThemeName]["base-content"],
@@ -38,12 +40,9 @@ export default function Layout() {
: rawTheme[colorScheme as ThemeName]["base-100"],
},
headerStyle: {
backgroundColor:
Platform.OS === "ios"
? "transparent"
: colorScheme === "dark"
? rawTheme["dark"]["base-100"]
: "white",
backgroundColor: isIOS26Plus
? "transparent"
: rawTheme[colorScheme as ThemeName]["base-100"],
},
}}
/>

View File

@@ -10,6 +10,8 @@ export default function Layout() {
const router = useRouter();
const { colorScheme } = useColorScheme();
const isIOS26Plus = Platform.OS === "ios" && Number(Platform.Version) >= 26;
return (
<Stack
screenOptions={{
@@ -18,7 +20,7 @@ export default function Layout() {
headerTintColor: colorScheme === "dark" ? "white" : "black",
headerShadowVisible: false,
headerLargeTitleStyle: {
color: rawTheme[colorScheme as ThemeName]["base-content"], // or whatever token you want
color: rawTheme[colorScheme as ThemeName]["base-content"],
},
headerTitleStyle: {
color: rawTheme[colorScheme as ThemeName]["base-content"],
@@ -30,12 +32,9 @@ export default function Layout() {
: rawTheme[colorScheme as ThemeName]["base-100"],
},
headerStyle: {
backgroundColor:
Platform.OS === "ios"
? "transparent"
: colorScheme === "dark"
? rawTheme["dark"]["base-100"]
: "white",
backgroundColor: isIOS26Plus
? "transparent"
: rawTheme[colorScheme as ThemeName]["base-100"],
},
}}
>

View File

@@ -7,6 +7,8 @@ export default function Layout() {
const router = useRouter();
const { colorScheme } = useColorScheme();
const isIOS26Plus = Platform.OS === "ios" && Number(Platform.Version) >= 26;
return (
<Stack
screenOptions={{
@@ -26,7 +28,7 @@ export default function Layout() {
headerIconColor: colorScheme === "dark" ? "white" : "black",
},
headerLargeTitleStyle: {
color: rawTheme[colorScheme as ThemeName]["base-content"], // or whatever token you want
color: rawTheme[colorScheme as ThemeName]["base-content"],
},
headerTitleStyle: {
color: rawTheme[colorScheme as ThemeName]["base-content"],
@@ -38,12 +40,9 @@ export default function Layout() {
: rawTheme[colorScheme as ThemeName]["base-100"],
},
headerStyle: {
backgroundColor:
Platform.OS === "ios"
? "transparent"
: colorScheme === "dark"
? rawTheme["dark"]["base-100"]
: "white",
backgroundColor: isIOS26Plus
? "transparent"
: rawTheme[colorScheme as ThemeName]["base-100"],
},
}}
/>

View File

@@ -1,10 +1,15 @@
import { Stack } from "expo-router";
import { Stack, useRouter } from "expo-router";
import { useColorScheme } from "nativewind";
import { rawTheme, ThemeName } from "@/lib/colors";
import { Platform } from "react-native";
import { Platform, View } from "react-native";
export default function Layout() {
const { colorScheme } = useColorScheme();
const router = useRouter();
const isIOS26Plus =
Platform.OS === "ios" && parseInt(Platform.Version as string, 10) >= 26;
const themeBackgroundColor = rawTheme[colorScheme as ThemeName]["base-100"];
return (
<Stack
@@ -12,37 +17,53 @@ export default function Layout() {
headerTitle: "Settings",
headerLargeTitle: true,
headerTintColor: colorScheme === "dark" ? "white" : "black",
headerTransparent: Platform.OS === "ios",
headerShadowVisible: false,
headerLargeTitleStyle: {
color: rawTheme[colorScheme as ThemeName]["base-content"], // or whatever token you want
color: rawTheme[colorScheme as ThemeName]["base-content"],
},
headerTitleStyle: {
color: rawTheme[colorScheme as ThemeName]["base-content"],
},
headerLargeStyle: {
backgroundColor:
Platform.OS === "ios"
? "transparent"
: rawTheme[colorScheme as ThemeName]["base-100"],
Platform.OS === "ios" ? "transparent" : themeBackgroundColor,
},
headerBackTitle: "Back",
headerStyle: {
backgroundColor:
Platform.OS === "ios"
? "transparent"
: colorScheme === "dark"
? rawTheme["dark"]["base-100"]
: "white",
backgroundColor: isIOS26Plus ? "transparent" : themeBackgroundColor,
},
}}
>
<Stack.Screen name="index" />
<Stack.Screen
name="index"
options={{
headerTransparent: Platform.OS === "ios",
}}
/>
<Stack.Screen
name="preferredCollection"
options={{
headerTitle: "Preferred Collection",
headerLargeTitle: false,
headerTransparent: Platform.OS === "ios",
headerBackground: () => (
<View
style={{
flex: 1,
backgroundColor: themeBackgroundColor,
}}
/>
),
headerSearchBarOptions: {
placeholder: "Search Collections",
autoCapitalize: "none",
onChangeText: (e) => {
router.setParams({
search: encodeURIComponent(e.nativeEvent.text),
});
},
headerIconColor: colorScheme === "dark" ? "white" : "black",
},
}}
/>
</Stack>

View File

@@ -1,27 +1,38 @@
import { View, Text, FlatList, TouchableOpacity } from "react-native";
import React, { useCallback, useMemo, useState } from "react";
import { View, Text, FlatList, TouchableOpacity, Platform } from "react-native";
import React, { useCallback, useEffect, useState } from "react";
import useAuthStore from "@/store/auth";
import useDataStore from "@/store/data";
import { useCollections } from "@linkwarden/router/collections";
import { CollectionIncludingMembersAndLinkCount } from "@linkwarden/types/global";
import Input from "@/components/ui/Input";
import { Folder, Check } from "lucide-react-native";
import { useColorScheme } from "nativewind";
import { rawTheme, ThemeName } from "@/lib/colors";
import { useLocalSearchParams } from "expo-router";
import { useHeaderHeight } from "@react-navigation/elements";
import { useSafeAreaInsets } from "react-native-safe-area-context";
const PreferredCollectionScreen = () => {
const { auth } = useAuthStore();
const { data, updateData } = useDataStore();
const collections = useCollections(auth);
const { colorScheme } = useColorScheme();
const [searchQuery, setSearchQuery] = useState("");
const { search } = useLocalSearchParams<{ search?: string }>();
const [filteredCollections, setFilteredCollections] = useState<
CollectionIncludingMembersAndLinkCount[]
>([]);
const headerHeight = useHeaderHeight();
const insets = useSafeAreaInsets();
const filteredCollections = useMemo(() => {
if (!collections.data) return [];
const q = searchQuery.trim().toLowerCase();
if (q === "") return collections.data;
return collections.data.filter((col) => col.name.toLowerCase().includes(q));
}, [collections.data, searchQuery]);
useEffect(() => {
const filter =
collections.data?.filter((e) =>
e.name
.toLowerCase()
.includes(decodeURIComponent(search?.toLowerCase() || ""))
) || [];
setFilteredCollections(filter);
}, [search, collections.data]);
const renderCollection = useCallback(
({
@@ -70,26 +81,19 @@ const PreferredCollectionScreen = () => {
keyExtractor={(item) => item.id?.toString() || ""}
renderItem={renderCollection}
contentContainerStyle={{
paddingHorizontal: 20,
paddingTop: 20,
paddingBottom: 20,
paddingHorizontal: 16,
flexGrow: 1,
paddingTop: Platform.OS === "ios" ? headerHeight + 10 : 10,
paddingBottom: insets.bottom + 60,
}}
contentInsetAdjustmentBehavior="automatic"
ListHeaderComponent={
<Input
placeholder="Search collections"
className="mb-4 bg-base-200 h-10"
value={searchQuery}
onChangeText={setSearchQuery}
/>
}
ListEmptyComponent={
<Text
style={{ textAlign: "center", marginTop: 20 }}
className="text-neutral"
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
No collections match {searchQuery}
</Text>
<Text className="text-neutral text-center">
No collections match {search}
</Text>
</View>
}
/>
</View>

View File

@@ -7,6 +7,8 @@ export default function Layout() {
const router = useRouter();
const { colorScheme } = useColorScheme();
const isIOS26Plus = Platform.OS === "ios" && Number(Platform.Version) >= 26;
return (
<Stack
screenOptions={{
@@ -26,24 +28,20 @@ export default function Layout() {
headerIconColor: colorScheme === "dark" ? "white" : "black",
},
headerLargeTitleStyle: {
color: rawTheme[colorScheme as ThemeName]["base-content"], // or whatever token you want
color: rawTheme[colorScheme as ThemeName]["base-content"],
},
headerTitleStyle: {
color: rawTheme[colorScheme as ThemeName]["base-content"],
},
headerLargeStyle: {
backgroundColor:
Platform.OS === "ios"
? "transparent"
: rawTheme[colorScheme as ThemeName]["base-100"],
backgroundColor: isIOS26Plus
? "transparent"
: rawTheme[colorScheme as ThemeName]["base-100"],
},
headerStyle: {
backgroundColor:
Platform.OS === "ios"
? "transparent"
: colorScheme === "dark"
? rawTheme["dark"]["base-100"]
: "white",
backgroundColor: isIOS26Plus
? "transparent"
: rawTheme[colorScheme as ThemeName]["base-100"],
},
}}
/>

View File

@@ -299,14 +299,10 @@ const RootComponent = ({
},
headerStyle: {
backgroundColor:
Platform.OS === "ios"
? "transparent"
: colorScheme === "dark"
? rawTheme["dark"]["base-100"]
: "white",
rawTheme[colorScheme as ThemeName]["base-100"],
},
headerRight: () => (
<View className="flex-row gap-5 px-2">
<View className="flex-row gap-5">
<TouchableOpacity
onPress={() => {
if (tmp.link) {