[nobuild] continue building skeleton UI - unfinished

This commit is contained in:
Stef-00012 2025-05-04 21:26:41 +02:00
parent 7e7b99754a
commit 7e23483dfb
No known key found for this signature in database
GPG key ID: 28BE9A9E4EF0E6BF
8 changed files with 461 additions and 137 deletions

View file

@ -46,6 +46,9 @@ import {
View,
} from "react-native";
import ColorPicker from "@/components/ColorPicker";
import SkeletonTable from "@/components/skeleton/Table";
import { Skeleton } from "moti/skeleton";
import { colors } from "@/constants/skeleton";
export default function Files() {
const router = useRouter();
@ -1177,30 +1180,58 @@ export default function Files() {
})}
/>
) : (
<>
<ScrollView showsVerticalScrollIndicator={false}>
{files.page.map((file) => (
<View key={file.id} style={styles.imageContainer}>
<FileDisplay
uri={`${url}/raw/${file.name}`}
width={filesWidth - 50}
originalName={file.originalName}
name={file.name}
autoHeight
passwordProtected={file.password}
file={file}
onPress={() => setFocusedFile(file)}
/>
</View>
))}
</ScrollView>
</>
<ScrollView showsVerticalScrollIndicator={false}>
{files.page.map((file) => (
<View key={file.id} style={styles.imageContainer}>
<FileDisplay
uri={`${url}/raw/${file.name}`}
width={filesWidth - 50}
originalName={file.originalName}
name={file.name}
autoHeight
passwordProtected={file.password}
file={file}
onPress={() => setFocusedFile(file)}
/>
</View>
))}
</ScrollView>
)}
</>
) : (
<View style={styles.loadingContainer}>
<Text style={styles.loadingText}>Loading...</Text>
</View>
<>
{compactModeEnabled ? (
<SkeletonTable
headerRow={[
"Name",
"Tags",
"Type",
"Size",
"Created At",
"Favorite",
"ID",
"Actions",
]}
rowWidth={[150, 150, 150, 80, 130, 100, 220, 170]}
rows={[...Array(10).keys()].map(() => {
return [80, 40, 60, 60, 90, 20, 120, 150];
})}
rowHeight={55}
disableAnimations
/>
) : (
<ScrollView showsVerticalScrollIndicator={false}>
{[...Array(4).keys()].map(index => (
<View key={index} style={{
marginVertical: 5,
marginHorizontal: 5
}}>
<Skeleton colors={colors} width="100%" height={250} />
</View>
))}
</ScrollView>
)}
</>
)}
</ScrollView>

View file

@ -21,6 +21,9 @@ import {
editFolder,
getFolders,
} from "@/functions/zipline/folders";
import SkeletonTable from "@/components/skeleton/Table";
import { Skeleton } from "moti/skeleton";
import { colors } from "@/constants/skeleton";
export type FolderActions =
| "viewFiles"
@ -675,9 +678,39 @@ export default function Folders() {
)}
</>
) : (
<View style={styles.loadingContainer}>
<Text style={styles.loadingText}>Loading...</Text>
</View>
<>
{compactModeEnabled ? (
<SkeletonTable
headerRow={[
"Name",
"Public",
"Uploads?",
"Created",
"Last Updated At",
"Files",
"ID",
"Actions",
]}
rowWidth={[140, 90, 110, 140, 150, 100, 220, 252]}
rows={[...Array(12).keys()].map(() => {
return [80, 30, 30, 90, 90, 40, 120, 200];
})}
rowHeight={55}
disableAnimations
/>
) : (
<ScrollView showsVerticalScrollIndicator={false}>
{[...Array(4).keys()].map(index => (
<View key={index} style={{
marginVertical: 5,
marginHorizontal: 5
}}>
<Skeleton colors={colors} width="100%" height={200} />
</View>
))}
</ScrollView>
)}
</>
)}
</View>
</View>

View file

@ -24,6 +24,9 @@ import {
type StatsProps,
} from "@/functions/zipline/stats";
import { MaterialIcons } from "@expo/vector-icons";
import { Skeleton } from "moti/skeleton";
import { colors } from "@/constants/skeleton";
import SkeletonTable from "@/components/skeleton/Table";
export default function Metrics() {
useAuth();
@ -222,7 +225,7 @@ export default function Metrics() {
difference: statsDifferences.files,
},
{
title: "URLs",
title: "URLs:",
amount: mainStat.data.urls,
difference: statsDifferences.urls,
},
@ -656,8 +659,166 @@ export default function Metrics() {
</ScrollView>
</View>
) : (
<View style={styles.loadingContainer}>
<Text style={styles.loadingText}>Loading...</Text>
<View style={styles.mainContainer}>
<Skeleton.Group show={!filteredStats || !mainStat}>
<ScrollView style={{ height: "93%" }}>
<ScrollView horizontal style={styles.scrollView}>
{[
"Files:",
"URLs:",
"Storage Used:",
"Users:",
"File Views:",
"URL Views:",
].map((stat) => (
<View key={stat} style={styles.statContainer}>
<Text style={styles.subHeaderText}>{stat}</Text>
<View style={styles.statContainerData}>
<Skeleton colors={colors} height={36} width={60} />
<View style={{
width: 5
}} />
<View style={{
marginTop: 9
}}>
<Skeleton colors={colors} height={27} width={40} />
</View>
</View>
</View>
))}
</ScrollView>
{userSpecificMetrics && (
<>
<View
style={{
...styles.chartContainer,
padding: 0,
}}
>
<SkeletonTable
headerRow={[
"User",
"URLs",
"Views",
]}
rowWidth={[190, 100, 100]}
rows={[[80, 50]]}
/>
</View>
<View
style={{
...styles.chartContainer,
padding: 0,
}}
>
<SkeletonTable
headerRow={[
"User",
"Files",
"Storage Used",
"Views",
]}
rowWidth={[150, 60, 130, 50]}
rows={[[70, 50, 100, 50]]}
/>
</View>
<View
style={{
...styles.chartContainer,
padding: 0,
}}
>
<SkeletonTable
headerRow={[
"Type",
"Files",
]}
rowWidth={[tableTypeWidth, tableFilesWidth]}
rows={[...Array(4).keys()].map(() => {
return ["55%", 30];
})}
/>
</View>
</>
)}
<View style={styles.chartContainer}>
<View style={styles.pieChartContainer}>
<Skeleton colors={colors} radius="round" width={250} height={250} />
</View>
<View style={{
flexDirection: "row",
marginTop: 10
}}>
{[...Array(5).keys()].map((index) => (
<View key={index} style={{
marginHorizontal: 2.5
}}>
<Skeleton colors={colors} width={60} height={16} />
</View>
))}
</View>
</View>
<View style={styles.chartContainer}>
<Text style={styles.chartTitle}>Count</Text>
<Skeleton colors={colors} width="100%" height={220} />
<ChartLegend
data={[
{
label: "Files",
color: "#323ea8",
},
{
label: "URLs",
color: "#2f9e44",
},
]}
/>
</View>
<View style={styles.chartContainer}>
<Text style={styles.chartTitle}>Views</Text>
<Skeleton colors={colors} width="100%" height={220} />
<ChartLegend
data={[
{
label: "File Views",
color: "#323ea8",
},
{
label: "URL Views",
color: "#2f9e44",
},
]}
/>
</View>
<View style={styles.chartContainer}>
<Text style={styles.chartTitle}>Storage Used</Text>
<Skeleton colors={colors} width="100%" height={220} />
<ChartLegend
data={[
{
label: "Storage Used",
color: "#323ea8",
},
]}
/>
</View>
</ScrollView>
</Skeleton.Group>
</View>
)}
</View>

View file

@ -24,6 +24,9 @@ import {
editURL,
getURLs,
} from "@/functions/zipline/urls";
import SkeletonTable from "@/components/skeleton/Table";
import { Skeleton } from "moti/skeleton";
import { colors } from "@/constants/skeleton";
export type URLActions =
| "copyShortLink"
@ -140,8 +143,8 @@ export default function Urls() {
switch (type) {
case "copyShortLink": {
const urlDest = url.vanity
? `${dashUrl}${settings?.urlsRoute === "/" ? "" : settings?.urlsRoute}/${url.vanity}`
: `${dashUrl}${settings?.urlsRoute === "/" ? "" : settings?.urlsRoute}/${url.code}`;
? `${dashUrl}${settings?.urlsRoute === "/" ? "" : settings?.urlsRoute || "/go"}/${url.vanity}`
: `${dashUrl}${settings?.urlsRoute === "/" ? "" : settings?.urlsRoute || "/go"}/${url.code}`;
const saved = await Clipboard.setStringAsync(urlDest);
@ -455,13 +458,13 @@ export default function Urls() {
}}
icon="add-link"
color="transparent"
iconColor={urls && settings && dashUrl ? "#2d3f70" : "#2d3f7055"}
iconColor={urls && dashUrl ? "#2d3f70" : "#2d3f7055"}
borderColor="#222c47"
borderWidth={2}
iconSize={30}
padding={4}
rippleColor="#283557"
disabled={!urls || !dashUrl || !settings}
disabled={!urls || !dashUrl}
margin={{
left: 2,
right: 2,
@ -479,13 +482,13 @@ export default function Urls() {
}}
icon={compactModeEnabled ? "view-module" : "view-agenda"}
color="transparent"
iconColor={urls && settings && dashUrl ? "#2d3f70" : "#2d3f7055"}
iconColor={urls && dashUrl ? "#2d3f70" : "#2d3f7055"}
borderColor="#222c47"
borderWidth={2}
iconSize={30}
padding={4}
rippleColor="#283557"
disabled={!urls || !dashUrl || !settings}
disabled={!urls || !dashUrl}
margin={{
left: 2,
right: 2,
@ -532,7 +535,7 @@ export default function Urls() {
<View style={{ flex: 1 }}>
<View style={styles.urlsContainer}>
{urls && settings && dashUrl ? (
{urls && dashUrl ? (
<>
{compactModeEnabled ? (
<Table
@ -644,7 +647,7 @@ export default function Urls() {
<Link
key={url.id}
href={
`${dashUrl}${settings.urlsRoute === "/" ? "" : settings.urlsRoute}/${url.code}` as ExternalPathString
`${dashUrl}${settings?.urlsRoute === "/" ? "" : settings?.urlsRoute || "/go"}/${url.code}` as ExternalPathString
}
style={{
...styles.rowText,
@ -661,7 +664,7 @@ export default function Urls() {
<Link
key={url.id}
href={
`${dashUrl}${settings.urlsRoute === "/" ? "" : settings.urlsRoute}/${url.vanity}` as ExternalPathString
`${dashUrl}${settings?.urlsRoute === "/" ? "" : settings?.urlsRoute || "/go"}/${url.vanity}` as ExternalPathString
}
style={{
...styles.rowText,
@ -783,7 +786,7 @@ export default function Urls() {
<LargeURLView
key={url.id}
url={url}
urlsRoute={settings.urlsRoute}
urlsRoute={settings?.urlsRoute || "/go"}
dashUrl={dashUrl}
onAction={onAction}
/>
@ -792,9 +795,40 @@ export default function Urls() {
)}
</>
) : (
<View style={styles.loadingContainer}>
<Text style={styles.loadingText}>Loading...</Text>
</View>
<>
{compactModeEnabled ? (
<SkeletonTable
headerRow={[
"Code",
"Vanity",
"Destination",
"Views",
"Max Views",
"Created",
"Enabled",
"ID",
"Actions",
]}
rowWidth={[100, 120, 300, 110, 140, 130, 100, 220, 130]}
rows={[...Array(12).keys()].map(() => {
return [60, 50, 200, 30, 30, 70, 40, 180, 90];
})}
rowHeight={55}
disableAnimations
/>
) : (
<ScrollView showsVerticalScrollIndicator={false}>
{[...Array(4).keys()].map(index => (
<View key={index} style={{
marginVertical: 5,
marginHorizontal: 5
}}>
<Skeleton colors={colors} width="100%" height={200} />
</View>
))}
</ScrollView>
)}
</>
)}
</View>
</View>

View file

@ -53,11 +53,13 @@ export default function Layout() {
</Host>
</Header>
) : (
<View style={styles.noInternetContainer}>
<Text style={styles.noInternetText}>
No internet connection.
</Text>
</View>
<Header>
<View style={styles.noInternetContainer}>
<Text style={styles.noInternetText}>
No internet connection.
</Text>
</View>
</Header>
)}
</GestureHandlerRootView>
</KeyboardProvider>

View file

@ -257,24 +257,31 @@ export default function Home() {
) : (
<View style={styles.mainContainer}>
<Skeleton.Group show={!user}>
<ScrollView style={{
marginTop: 5
}}>
<View>
<Skeleton colors={colors} width="70%" height={28} />
<ScrollView
style={{
marginTop: 5,
}}
>
<View
style={{
flexDirection: "row",
}}
>
<Text style={styles.mainHeader}>Welcome back, </Text>
<Skeleton colors={colors} width="60%" height={36} />
</View>
<View style={{
marginTop: 5
}}>
<Skeleton colors={colors} width="50%" height={16} />
<View
style={{
marginTop: 5,
}}
>
<Text style={styles.subHeader}>
You have ## files uploaded.
</Text>
</View>
<View style={{
marginTop: 7
}}>
<Skeleton colors={colors} width="30%" height={28} />
</View>
<Text style={styles.headerText}>Recent Files</Text>
<ScrollView horizontal style={styles.scrollView}>
{[1, 2, 3].map((file) => (
@ -289,11 +296,7 @@ export default function Home() {
))}
</ScrollView>
<View style={{
marginTop: 7
}}>
<Skeleton colors={colors} width="20%" height={28} />
</View>
<Text style={styles.headerText}>Stats</Text>
<ScrollView
horizontal
@ -301,24 +304,35 @@ export default function Home() {
...styles.scrollView,
}}
>
{
[1, 2, 3, 4, 5, 6, 7, 8].map(stat => (
<View key={stat} style={{
marginHorizontal: 4,
marginVertical: 7.5
}}>
<Skeleton colors={colors} width={170} height={100} />
{[
["Files Uploaded:", 60],
["Favorite Files:", 50],
["Storage Used:", 90],
["Average Storage Used:", 70],
["File Views:", 50],
["File Average Views:", 50],
["Links Created:", 60],
["Total Link View:", 50],
].map((stat) => (
<View key={stat[0]} style={styles.statContainer}>
<Text style={styles.subHeaderText}>{stat[0]}</Text>
<View
style={{
marginTop: 5,
}}
>
<Skeleton
colors={colors}
width={stat[1] as number}
height={36}
/>
</View>
))
}
</View>
))}
</ScrollView>
<View style={{
marginTop: 7
}}>
<Skeleton colors={colors} width="20%" height={28} />
</View>
<Text style={styles.headerText}>File Types</Text>
<View
style={{
...styles.scrollView,
@ -326,17 +340,10 @@ export default function Home() {
}}
>
<SkeletonTable
headerRow={[
{
row: "File Type",
},
{
row: "Count",
},
]}
headerRow={["File Type", "Count"]}
rowWidth={[250, 150]}
rows={[...Array(10).keys()].map((index) => {
return ["55%", 30]
rows={[...Array(4).keys()].map(() => {
return ["55%", 30];
})}
/>
</View>

View file

@ -11,6 +11,8 @@ import Sidebar from "@/components/Sidebar";
import type React from "react";
import { useShareIntent } from "@/hooks/useShareIntent";
import { getRippleColor } from "@/functions/util";
import { Skeleton } from "moti/skeleton";
import { colors } from "@/constants/skeleton";
export default function Header({ children }: PropsWithChildren) {
const router = useRouter();
@ -25,13 +27,7 @@ export default function Header({ children }: PropsWithChildren) {
useEffect(() => {
if (!avatar || !user) {
(async () => {
const avatar = await getCurrentUserAvatar();
const user = await getCurrentUser();
setAvatar(avatar);
setUser(typeof user === "string" ? null : user);
})();
fetchUser()
}
}, [avatar, user]);
@ -103,7 +99,43 @@ export default function Header({ children }: PropsWithChildren) {
</View>
</View>
) : (
<View />
<View
style={{
marginBottom: 70,
}}
>
<Skeleton.Group show={!user}>
<View style={styles.header}>
<View style={styles.headerLeft}>
<IconButton
disabled
icon={() => (
<MaterialIcons name="menu" color={"#ffffff77"} size={40} />
)}
android_ripple={{
color: getRippleColor("#0c101c")
}}
onPress={() => {
setSidebarOpen((prev) => !prev);
}}
/>
</View>
<Stack>
<View>
<View
style={{
padding: 10,
borderRadius: 10
}}
>
<Skeleton colors={colors} height={36} width={80} />
</View>
</View>
</Stack>
</View>
</Skeleton.Group>
</View>
)}
<Sidebar
open={sidebarOpen}

View file

@ -2,42 +2,39 @@ import { Table as NativeTable, Row } from "react-native-reanimated-table";
import { styles } from "@/styles/components/table";
import { Skeleton } from "moti/skeleton";
import { colors } from "@/constants/skeleton";
import {
Pressable,
ScrollView,
Text,
View,
type DimensionValue,
} from "react-native";
import { ScrollView, Text, View, type DimensionValue } from "react-native";
import type { ReactNode } from "react";
interface Props {
headerRow: Array<string>;
rows: Array<Array<DimensionValue>>;
rowWidth: Array<number>;
headerRow: Array<ReactNode>;
rows: Array<Array<DimensionValue>>;
rowWidth: Array<number>;
rowHeight?: DimensionValue;
disableAnimations?: boolean;
}
export default function SkeletonTable({
headerRow,
rows,
rowWidth
headerRow,
rows,
rowWidth,
rowHeight,
disableAnimations,
}: Props) {
const updatedHeaderRow = headerRow.map((row) => {
return ["string", "number", "boolean"].includes(typeof row.row) ? (
<Text
style={{
...styles.rowText,
...styles.headerRow,
}}
>
{row.row}
</Text>
) : (
row.row
)
})
return (
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
const updatedHeaderRow = headerRow.map((row, index) => (
<Text
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
key={index}
style={{
...styles.rowText,
...styles.headerRow,
}}
>
{row}
</Text>
));
return (
<ScrollView showsHorizontalScrollIndicator={false} horizontal>
<View>
<NativeTable>
<Row
@ -57,25 +54,52 @@ export default function SkeletonTable({
>
<NativeTable>
{rows.map((row, index) => {
let rowStyle = styles.row;
let rowStyle = {
...styles.row,
...(rowHeight && { height: rowHeight }),
};
if (index === 0)
rowStyle = {
...styles.row,
...styles.firstRow,
...(rowHeight && { height: rowHeight }),
};
if (index === rows.length - 1)
rowStyle = {
...styles.row,
...styles.lastRow,
...(rowHeight && { height: rowHeight }),
};
const rowData = row.map(data => {
return (
<Skeleton colors={colors} height={14} width={data} />
)
})
const rowData = row.map((data, index) => {
return (
<>
{disableAnimations ? (
<View
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
key={index}
style={{
backgroundColor: colors[1],
height: 14,
width: data,
borderRadius: 8
}}
/>
) : (
<Skeleton
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
key={index}
colors={colors}
height={14}
width={data}
/>
)}
</>
);
});
return (
<Row
@ -92,5 +116,5 @@ export default function SkeletonTable({
</ScrollView>
</View>
</ScrollView>
)
}
);
}