feat: update ui

This commit is contained in:
2024-11-08 18:24:08 +07:00
parent ca3fe7150b
commit 887cb64878
19 changed files with 45204 additions and 57 deletions
+3 -8
View File
@@ -1,20 +1,15 @@
import {
DarkTheme,
DefaultTheme,
ThemeProvider,
} from "@react-navigation/native";
import { useFonts } from "expo-font";
import { Stack } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import { StatusBar } from "expo-status-bar";
import { useEffect } from "react";
import "react-native-reanimated";
import Providers from "./_providers";
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const colorScheme: string = "light";
const [loaded] = useFonts({
SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
});
@@ -30,11 +25,11 @@ export default function RootLayout() {
}
return (
<ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
<Providers>
<Stack>
<Stack.Screen name="+not-found" />
</Stack>
<StatusBar style="auto" />
</ThemeProvider>
</Providers>
);
}
+48
View File
@@ -0,0 +1,48 @@
import React, { PropsWithChildren, useMemo, useState } from "react";
import tamaguiConfig from "@/tamagui.config";
import {
DarkTheme,
DefaultTheme,
ThemeProvider,
} from "@react-navigation/native";
import { TamaguiProvider, Theme } from "@tamagui/core";
import useThemeStore from "@/stores/theme";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
type Props = PropsWithChildren;
const Providers = ({ children }: Props) => {
const colorScheme = useThemeStore((i) => i.theme);
const [queryClient] = useState(() => new QueryClient());
const theme = useMemo(() => {
return colorScheme === "dark"
? tamaguiConfig.themes.dark_blue
: tamaguiConfig.themes.light_blue;
}, [colorScheme]);
const navTheme = useMemo(() => {
const base = colorScheme === "dark" ? DarkTheme : DefaultTheme;
return {
...base,
colors: {
...base.colors,
background: theme.background.val,
},
};
}, [theme, colorScheme]);
return (
<ThemeProvider value={navTheme}>
<TamaguiProvider config={tamaguiConfig} defaultTheme={colorScheme}>
<Theme name="blue">
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</Theme>
</TamaguiProvider>
</ThemeProvider>
);
};
export default Providers;
+69
View File
@@ -0,0 +1,69 @@
import Icons from "@/components/ui/icons";
import Select, { SelectItem } from "@/components/ui/select";
import api from "@/lib/api";
import { useQuery } from "@tanstack/react-query";
import React from "react";
import { Button, Input, Label, ScrollView, Text, View, XStack } from "tamagui";
type Props = {};
const typeOptions: SelectItem[] = [
{ label: "SSH", value: "ssh" },
{ label: "Proxmox VE", value: "pve" },
{ label: "Incus", value: "incus" },
];
const HostForm = (props: Props) => {
const keys = useQuery({
queryKey: ["keychains"],
queryFn: () => api("/keychains"),
select: (i) => i.rows,
});
return (
<>
<ScrollView contentContainerStyle={{ padding: "$4" }}>
<Label>Hostname</Label>
<Input placeholder="IP or hostname..." />
<Label>Type</Label>
<Select items={typeOptions} />
<Label>Port</Label>
<Input keyboardType="number-pad" placeholder="SSH Port" />
<Label>Label</Label>
<Input placeholder="Label..." />
<XStack gap="$3" mt="$3" mb="$1">
<Label flex={1}>Credentials</Label>
<Button size="$3" icon={<Icons size={16} name="plus" />}>
Add
</Button>
</XStack>
<Select
placeholder="Username & Password"
items={keys.data?.map((key: any) => ({
label: key.label,
value: key.id,
}))}
/>
<Select
mt="$3"
placeholder="Private Key"
items={keys.data?.map((key: any) => ({
label: key.label,
value: key.id,
}))}
/>
</ScrollView>
<View p="$4">
<Button icon={<Icons name="content-save" size={18} />}>Save</Button>
</View>
</>
);
};
export default HostForm;
+12
View File
@@ -0,0 +1,12 @@
import React from "react";
import { Stack } from "expo-router";
import HostForm from "./_comp/host-form";
export default function CreateHostPage() {
return (
<>
<Stack.Screen options={{ title: "Add Host" }} />
<HostForm />
</>
);
}
+12
View File
@@ -0,0 +1,12 @@
import React from "react";
import { Stack } from "expo-router";
import HostForm from "./_comp/host-form";
export default function EditHostPage() {
return (
<>
<Stack.Screen options={{ title: "Edit Host" }} />
<HostForm />
</>
);
}
+80
View File
@@ -0,0 +1,80 @@
import { View, Text, Button, ScrollView, Spinner, Card, XStack } from "tamagui";
import React from "react";
import useThemeStore from "@/stores/theme";
import { useQuery } from "@tanstack/react-query";
import api from "@/lib/api";
import { Stack } from "expo-router";
import Pressable from "@/components/ui/pressable";
import Icons from "@/components/ui/icons";
export default function Hosts() {
const { toggle } = useThemeStore();
const hosts = useQuery({
queryKey: ["hosts"],
queryFn: () => api("/hosts"),
});
return (
<>
<Stack.Screen
options={{
title: "Hosts",
headerRight: () => (
<Button onPress={() => toggle()} mr="$2">
Toggle Theme
</Button>
),
}}
/>
{hosts.isLoading ? (
<View alignItems="center" justifyContent="center" flex={1}>
<Spinner size="large" />
<Text mt="$4">Loading...</Text>
</View>
) : (
<ScrollView
contentContainerStyle={{
padding: "$2",
flexDirection: "row",
flexWrap: "wrap",
// gap: "$4",
}}
>
{hosts.data.rows?.map((host: any) => (
<Pressable
key={host.id}
flexBasis="100%"
$gtXs={{ flexBasis: "50%" }}
$gtSm={{ flexBasis: "33.3%" }}
$gtMd={{ flexBasis: "25%" }}
$gtLg={{ flexBasis: "20%" }}
p="$2"
group
>
<Card elevate bordered p="$4">
<XStack>
<View flex={1}>
<Text>{host.label}</Text>
<Text fontSize="$3" mt="$2">
{host.host}
</Text>
</View>
<Button
circular
display="none"
$group-hover={{ display: "block" }}
>
<Icons name="pencil" size={16} />
</Button>
</XStack>
</Card>
</Pressable>
))}
</ScrollView>
)}
</>
);
}
+6
View File
@@ -0,0 +1,6 @@
import React from "react";
import { Redirect } from "expo-router";
export default function index() {
return <Redirect href="/hosts" />;
}