mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-08 03:42:49 +00:00
Mobile Strict Mode and Types (#578)
* better compiler options * fix types * fix more types
This commit is contained in:
parent
32ffd5f820
commit
7b739d0b33
|
@ -10,7 +10,7 @@ interface Props {
|
|||
}
|
||||
|
||||
export default function DocsSidebar(props: Props) {
|
||||
const activeSection = props.activePath?.split('/')[0] || props.navigation[0].slug;
|
||||
const activeSection = props.activePath?.split('/')[0] || props.navigation[0]?.slug;
|
||||
|
||||
const activeSectionData = props.navigation.find((section) => section.slug === activeSection);
|
||||
|
||||
|
@ -27,7 +27,7 @@ export default function DocsSidebar(props: Props) {
|
|||
const Icon = config.sections.find((s) => s.slug === section.slug)?.icon;
|
||||
return (
|
||||
<a
|
||||
href={`/docs/${section.section[0].category[0].url}`}
|
||||
href={`/docs/${section.section[0]?.category[0]?.url}`}
|
||||
key={section.slug}
|
||||
className={clsx(
|
||||
`doc-sidebar-button flex items-center py-1.5 text-[14px] font-semibold`,
|
||||
|
|
|
@ -2,7 +2,7 @@ import { PageContextBuiltIn } from 'vite-plugin-ssr';
|
|||
import { getPost } from './blog';
|
||||
|
||||
export async function onBeforeRender(pageContext: PageContextBuiltIn) {
|
||||
const post = await getPost(pageContext.routeParams['slug']);
|
||||
const post = await getPost(pageContext.routeParams['slug']!);
|
||||
|
||||
return {
|
||||
pageContext: {
|
||||
|
|
|
@ -47,13 +47,13 @@ export function getDocs(config: DocsConfig): Record<string, Doc> {
|
|||
const url = parsePath(path);
|
||||
if (!url) return null;
|
||||
|
||||
const { render, metadata } = parseMarkdown(config.docs[path]);
|
||||
const { render, metadata } = parseMarkdown(config.docs[path]!);
|
||||
|
||||
parsedDocs[url] = {
|
||||
title: metadata?.name ?? toTitleCase(url.split('/')[2]),
|
||||
slug: url.split('/')[2],
|
||||
title: metadata?.name ?? toTitleCase(url.split('/')[2]!),
|
||||
slug: url.split('/')[2]!,
|
||||
url,
|
||||
categoryName: toTitleCase(url.split('/')[1]),
|
||||
categoryName: toTitleCase(url.split('/')[1]!),
|
||||
sortByIndex: metadata?.index ?? DEFAULT_INDEX,
|
||||
html: render
|
||||
};
|
||||
|
@ -77,15 +77,15 @@ export function getDocsNavigation(config: DocsConfig, docs?: Record<string, Doc>
|
|||
delete clonedDoc.html;
|
||||
|
||||
const category = url.split('/')[1],
|
||||
title = toTitleCase(category),
|
||||
title = toTitleCase(category!),
|
||||
existingCategory = categories.findIndex((i) => i.slug === category);
|
||||
|
||||
if (existingCategory != -1) {
|
||||
categories[existingCategory].category.push(clonedDoc);
|
||||
categories[existingCategory]?.category.push(clonedDoc);
|
||||
} else {
|
||||
categories.push({
|
||||
title,
|
||||
slug: category,
|
||||
slug: category!,
|
||||
index: DEFAULT_INDEX,
|
||||
category: [clonedDoc]
|
||||
});
|
||||
|
@ -98,7 +98,7 @@ export function getDocsNavigation(config: DocsConfig, docs?: Record<string, Doc>
|
|||
return cat;
|
||||
})
|
||||
// sort categories smallest first doc's index
|
||||
.sort((a, b) => a.category[0].sortByIndex - b.category[0].sortByIndex);
|
||||
.sort((a, b) => a.category[0]!.sortByIndex - b.category[0]!.sortByIndex);
|
||||
|
||||
navigation.push({
|
||||
title: section.title,
|
||||
|
@ -134,8 +134,8 @@ export function getDoc(url: string, config: DocsConfig): SingleDocResponse {
|
|||
}
|
||||
|
||||
function parsePath(path: string): string | null {
|
||||
const url = path.split('docs/')[1].split('.md')[0];
|
||||
if (!url.includes('/')) return null;
|
||||
const url = path.split('docs/')[1]!.split('.md')[0];
|
||||
if (!url?.includes('/')) return null;
|
||||
return url;
|
||||
}
|
||||
|
||||
|
@ -153,7 +153,7 @@ type DocUrls = { url: string; title: string }[];
|
|||
export function getNextDoc(
|
||||
navigation: DocsNavigation,
|
||||
docUrl: string
|
||||
): { url: string; title: string } {
|
||||
): { url: string; title: string } | undefined {
|
||||
const docUrls: DocUrls = [];
|
||||
// flatten the navigation
|
||||
for (const section of navigation) {
|
||||
|
|
|
@ -7,7 +7,7 @@ export const passToClient = ['pageProps'];
|
|||
export async function onBeforeRender(pageContext: PageContextBuiltIn) {
|
||||
return {
|
||||
pageContext: {
|
||||
pageProps: getDoc(pageContext.routeParams['*'], config)
|
||||
pageProps: getDoc(pageContext.routeParams['*']!, config)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ const teamMembers: Array<TeamMemberProps> = [
|
|||
{
|
||||
name: 'Jamie Pine',
|
||||
role: 'Founder, Engineer & Designer',
|
||||
image: teamImages['jamie.jpg'],
|
||||
image: teamImages['jamie.jpg']!,
|
||||
socials: {
|
||||
twitter: 'https://twitter.com/jamiepine',
|
||||
twitch: 'https://twitch.tv/jamiepinelive',
|
||||
|
@ -21,7 +21,7 @@ const teamMembers: Array<TeamMemberProps> = [
|
|||
{
|
||||
name: 'Brendan Allan',
|
||||
role: 'Rust Engineer',
|
||||
image: teamImages['brendan.jpg'],
|
||||
image: teamImages['brendan.jpg']!,
|
||||
socials: {
|
||||
twitter: 'https://twitter.com/brendonovichdev',
|
||||
twitch: 'https://twitch.tv/brendonovich',
|
||||
|
@ -31,7 +31,7 @@ const teamMembers: Array<TeamMemberProps> = [
|
|||
{
|
||||
name: 'Oscar Beaumont',
|
||||
role: 'Rust Engineer',
|
||||
image: teamImages['oscar.jpg'],
|
||||
image: teamImages['oscar.jpg']!,
|
||||
socials: {
|
||||
twitter: 'https://twitter.com/oscartbeaumont',
|
||||
twitch: 'https://twitch.tv/oscartbeaumont',
|
||||
|
@ -41,16 +41,16 @@ const teamMembers: Array<TeamMemberProps> = [
|
|||
{
|
||||
name: 'Ericson Soares',
|
||||
role: 'Rust Engineer',
|
||||
image: teamImages['ericson.jpg'],
|
||||
image: teamImages['ericson.jpg']!,
|
||||
socials: {
|
||||
twitter: 'https://twitter.com/fogodev',
|
||||
github: 'https://github.com/fogodev'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Utku Bakir',
|
||||
name: 'Utku Bakır',
|
||||
role: 'React Native Engineer',
|
||||
image: teamImages['utku.jpg'],
|
||||
image: teamImages['utku.jpg']!,
|
||||
socials: {
|
||||
github: 'https://github.com/utkubakir'
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ const teamMembers: Array<TeamMemberProps> = [
|
|||
{
|
||||
name: 'Haden Fletcher',
|
||||
role: 'Engineer & Designer',
|
||||
image: teamImages['haden.jpg'],
|
||||
image: teamImages['haden.jpg']!,
|
||||
socials: {
|
||||
twitter: 'https://twitter.com/heymaxichrome',
|
||||
twitch: 'https://twitch.tv/maxichrome',
|
||||
|
@ -68,7 +68,7 @@ const teamMembers: Array<TeamMemberProps> = [
|
|||
{
|
||||
name: 'Jake Robinson',
|
||||
role: 'Rust Engineer',
|
||||
image: teamImages['jake.jpg'],
|
||||
image: teamImages['jake.jpg']!,
|
||||
socials: {
|
||||
github: 'https://github.com/brxken128'
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ const teamMembers: Array<TeamMemberProps> = [
|
|||
{
|
||||
name: 'Mihail Dounaev',
|
||||
role: 'Graphic Designer',
|
||||
image: teamImages['mihail.jpg'],
|
||||
image: teamImages['mihail.jpg']!,
|
||||
socials: {
|
||||
twitter: 'https://twitter.com/mmmintdesign',
|
||||
dribbble: 'https://dribbble.com/mmmint'
|
||||
|
@ -89,109 +89,109 @@ const investors: Array<TeamMemberProps> = [
|
|||
name: 'Joseph Jacks',
|
||||
role: 'Founder, OSSC',
|
||||
investmentRound: 'Lead Seed',
|
||||
image: investorImages['josephjacks.jpg']
|
||||
image: investorImages['josephjacks.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Guillermo Rauch',
|
||||
role: 'CEO, Vercel',
|
||||
investmentRound: 'Co-Lead Seed',
|
||||
image: investorImages['guillermo.jpg']
|
||||
image: investorImages['guillermo.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Naval Ravikant',
|
||||
role: 'Founder, AngelList',
|
||||
investmentRound: 'Co-Lead Seed',
|
||||
image: investorImages['naval.jpg']
|
||||
image: investorImages['naval.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Neha Narkhede',
|
||||
role: 'Confluent, Apache Kafka',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['neha.jpg']
|
||||
image: investorImages['neha.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Austen Allred',
|
||||
role: 'CEO, Bloom Institute of Technology',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['austen.jpg']
|
||||
image: investorImages['austen.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Tom Preston-Werner',
|
||||
role: 'Founder, GitHub',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['TOM.jpg']
|
||||
image: investorImages['TOM.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Tobias Lütke',
|
||||
role: 'CEO, Shopify',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['tobiaslutke.jpg']
|
||||
image: investorImages['tobiaslutke.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Justin Hoffman',
|
||||
role: 'Former VP Sales, Elasticsearch',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['justinhoffman.jpg']
|
||||
image: investorImages['justinhoffman.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Ry Walker',
|
||||
role: 'Founder, Astronomer',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['rywalker.jpg']
|
||||
image: investorImages['rywalker.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Zachary Smith',
|
||||
role: 'Head of Edge Infrastructure, Equinix',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['zacharysmith.jpg']
|
||||
image: investorImages['zacharysmith.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Sanjay Poonen',
|
||||
role: 'Former COO, VMware',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['sanjay.jpg']
|
||||
image: investorImages['sanjay.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'David Mytton',
|
||||
role: 'CEO, console.dev',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['davidmytton.jpg']
|
||||
image: investorImages['davidmytton.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Peer Richelsen',
|
||||
role: 'CEO, Cal.com',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['peer.jpg']
|
||||
image: investorImages['peer.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Lester Lee',
|
||||
role: 'Founder, Slapdash',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['lesterlee.jpg']
|
||||
image: investorImages['lesterlee.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Haoyuan Li',
|
||||
role: 'Founder, Alluxio',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['haoyuan.jpg']
|
||||
image: investorImages['haoyuan.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Augusto Marietti',
|
||||
role: 'CEO, Kong',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['augusto.jpg']
|
||||
image: investorImages['augusto.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Vijay Sharma',
|
||||
role: 'CEO, Belong',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['vijay.jpg']
|
||||
image: investorImages['vijay.jpg']!
|
||||
},
|
||||
{
|
||||
name: 'Naveen R',
|
||||
role: 'Founder, NocoDB',
|
||||
investmentRound: 'Seed',
|
||||
image: investorImages['naveen.jpg']
|
||||
image: investorImages['naveen.jpg']!
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -41,10 +41,10 @@ export function parseMarkdown(markdownRaw: string): MarkdownParsed {
|
|||
return text;
|
||||
} else {
|
||||
const rawText = rawSplit[index],
|
||||
meta = rawText.split(/\r?\n/)[0].trim(),
|
||||
meta = rawText!.split(/\r?\n/)[0]!.trim(),
|
||||
kind = meta.split(' ')[0],
|
||||
name = meta.split(' ')[1],
|
||||
extra = meta.substring(kind.length + name.length + 2),
|
||||
extra = meta.substring(kind!.length + name!.length + 2),
|
||||
content = text.substring(meta.length + 1, text.length).trim();
|
||||
|
||||
// console.log({ kind, name, extra, content });
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// @ts-check
|
||||
// @ts-ignore
|
||||
let fs = require('fs-extra');
|
||||
let path = require('path');
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useState } from 'react';
|
||||
import { queryClient, useBridgeMutation } from '@sd/client';
|
||||
import { Input } from '~/components/form/Input';
|
||||
import Dialog from '~/components/layout/Dialog';
|
||||
import { Input } from '~/components/primitive/Input';
|
||||
import { currentLibraryStore } from '~/utils/nav';
|
||||
|
||||
type Props = {
|
||||
|
|
|
@ -35,7 +35,7 @@ const DrawerLibraryManager = () => {
|
|||
: 'border-b-app-box border-sidebar-line bg-sidebar-button rounded-t-md'
|
||||
)}
|
||||
>
|
||||
<Text style={tw`text-ink text-sm font-semibold`}>{currentLibrary.config.name}</Text>
|
||||
<Text style={tw`text-ink text-sm font-semibold`}>{currentLibrary?.config.name}</Text>
|
||||
<MotiView
|
||||
animate={{
|
||||
rotate: dropdownClosed ? '0deg' : '180deg',
|
||||
|
@ -57,13 +57,13 @@ const DrawerLibraryManager = () => {
|
|||
<View
|
||||
style={twStyle(
|
||||
'mt-1 p-2',
|
||||
currentLibrary.uuid === library.uuid && 'bg-accent rounded'
|
||||
currentLibrary?.uuid === library.uuid && 'bg-accent rounded'
|
||||
)}
|
||||
>
|
||||
<Text
|
||||
style={twStyle(
|
||||
'text-ink text-sm font-semibold',
|
||||
currentLibrary.uuid === library.uuid && 'text-white'
|
||||
currentLibrary?.uuid === library.uuid && 'text-white'
|
||||
)}
|
||||
>
|
||||
{library.config.name}
|
||||
|
|
|
@ -36,7 +36,7 @@ type DrawerLocationsProp = {
|
|||
const DrawerLocations = ({ stackName }: DrawerLocationsProp) => {
|
||||
const navigation = useNavigation<DrawerNavigationHelpers>();
|
||||
|
||||
const importModalRef = useRef<ModalRef>();
|
||||
const importModalRef = useRef<ModalRef>(null);
|
||||
|
||||
const { data: locations } = useLibraryQuery(['locations.list'], { keepPreviousData: true });
|
||||
|
||||
|
@ -62,7 +62,7 @@ const DrawerLocations = ({ stackName }: DrawerLocationsProp) => {
|
|||
))}
|
||||
</View>
|
||||
{/* Add Location */}
|
||||
<Pressable onPress={() => importModalRef.current.present()}>
|
||||
<Pressable onPress={() => importModalRef.current?.present()}>
|
||||
<View style={tw`border-app-line/80 mt-1 rounded border border-dashed`}>
|
||||
<Text style={tw`p-2 text-center text-xs font-bold text-gray-400`}>Add Location</Text>
|
||||
</View>
|
||||
|
|
|
@ -37,7 +37,7 @@ const DrawerTags = ({ stackName }: DrawerTagsProp) => {
|
|||
|
||||
const { data: tags } = useLibraryQuery(['tags.list'], { keepPreviousData: true });
|
||||
|
||||
const createTagModalRef = useRef<ModalRef>();
|
||||
const createTagModalRef = useRef<ModalRef>(null);
|
||||
|
||||
return (
|
||||
<CollapsibleView
|
||||
|
@ -49,7 +49,7 @@ const DrawerTags = ({ stackName }: DrawerTagsProp) => {
|
|||
{tags?.map((tag) => (
|
||||
<DrawerTagItem
|
||||
key={tag.id}
|
||||
tagName={tag.name}
|
||||
tagName={tag.name!}
|
||||
onPress={() =>
|
||||
navigation.navigate(stackName, {
|
||||
screen: 'Tag',
|
||||
|
@ -61,7 +61,7 @@ const DrawerTags = ({ stackName }: DrawerTagsProp) => {
|
|||
))}
|
||||
</View>
|
||||
{/* Add Tag */}
|
||||
<Pressable onPress={() => createTagModalRef.current.present()}>
|
||||
<Pressable onPress={() => createTagModalRef.current?.present()}>
|
||||
<View style={tw`border-app-line/80 mt-1 rounded border border-dashed`}>
|
||||
<Text style={tw`p-2 text-center text-xs font-bold text-gray-400`}>Add Tag</Text>
|
||||
</View>
|
||||
|
|
|
@ -14,7 +14,7 @@ import FileItem from './FileItem';
|
|||
import FileRow from './FileRow';
|
||||
|
||||
type ExplorerProps = {
|
||||
data: ExplorerData;
|
||||
data: ExplorerData | undefined;
|
||||
};
|
||||
|
||||
const Explorer = ({ data }: ExplorerProps) => {
|
||||
|
@ -22,7 +22,7 @@ const Explorer = ({ data }: ExplorerProps) => {
|
|||
|
||||
const [layoutMode, setLayoutMode] = useState<'grid' | 'list'>(getExplorerStore().layoutMode);
|
||||
|
||||
function changeLayoutMode(kind) {
|
||||
function changeLayoutMode(kind: 'grid' | 'list') {
|
||||
// We need to keep layoutMode as a state to make sure flash-list re-renders.
|
||||
setLayoutMode(kind);
|
||||
getExplorerStore().layoutMode = kind;
|
||||
|
@ -35,7 +35,7 @@ const Explorer = ({ data }: ExplorerProps) => {
|
|||
navigation.push('Location', { id: data.item.location_id, path: data.item.materialized_path });
|
||||
} else {
|
||||
setData(data);
|
||||
modalRef.current.present();
|
||||
modalRef.current?.present();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { PropsWithChildren } from 'react';
|
||||
import { Image, View } from 'react-native';
|
||||
import { DocumentDirectoryPath } from 'react-native-fs';
|
||||
import { ExplorerItem, isObject, isPath } from '@sd/client';
|
||||
|
@ -18,7 +19,7 @@ type FileThumbProps = {
|
|||
export const getThumbnailUrlById = (casId: string) =>
|
||||
`${DocumentDirectoryPath}/thumbnails/${encodeURIComponent(casId)}.webp`;
|
||||
|
||||
const FileThumbWrapper = ({ children, size = 1 }) => (
|
||||
const FileThumbWrapper = ({ children, size = 1 }: PropsWithChildren<{ size: number }>) => (
|
||||
<View style={[tw`items-center justify-center`, { width: 80 * size, height: 80 * size }]}>
|
||||
{children}
|
||||
</View>
|
||||
|
@ -38,7 +39,7 @@ export default function FileThumb({ data, size = 1, kind }: FileThumbProps) {
|
|||
);
|
||||
|
||||
const casId = isObject(data) ? data.item.file_paths[0]?.cas_id : data.item.cas_id;
|
||||
if (!casId) return undefined;
|
||||
if (!casId) return null;
|
||||
|
||||
// Icon
|
||||
let icon = undefined;
|
||||
|
|
|
@ -12,7 +12,7 @@ type Props = {
|
|||
const InfoTagPills = ({ data, style }: Props) => {
|
||||
const objectData = data ? (isObject(data) ? data.item : data.item.object) : null;
|
||||
|
||||
const tagsQuery = useLibraryQuery(['tags.getForObject', objectData?.id], {
|
||||
const tagsQuery = useLibraryQuery(['tags.getForObject', objectData?.id ?? -1], {
|
||||
enabled: Boolean(objectData)
|
||||
});
|
||||
|
||||
|
@ -25,7 +25,7 @@ const InfoTagPills = ({ data, style }: Props) => {
|
|||
{/* Kind */}
|
||||
<InfoPill
|
||||
containerStyle={tw`mr-1`}
|
||||
text={isDir ? 'Folder' : ObjectKind[objectData?.kind || 0]}
|
||||
text={isDir ? 'Folder' : ObjectKind[objectData?.kind || 0]!}
|
||||
/>
|
||||
{/* Extension */}
|
||||
{item.extension && <InfoPill text={item.extension} containerStyle={tw`mr-1`} />}
|
||||
|
@ -33,7 +33,7 @@ const InfoTagPills = ({ data, style }: Props) => {
|
|||
{tagsQuery.data?.map((tag) => (
|
||||
<InfoPill
|
||||
key={tag.id}
|
||||
text={tag.name}
|
||||
text={tag.name ?? 'Unnamed Tag'}
|
||||
containerStyle={twStyle('mr-1', { backgroundColor: tag.color + 'CC' })}
|
||||
textStyle={tw`text-white`}
|
||||
/>
|
||||
|
|
38
apps/mobile/src/components/form/ColorPicker.tsx
Normal file
38
apps/mobile/src/components/form/ColorPicker.tsx
Normal file
|
@ -0,0 +1,38 @@
|
|||
import React from 'react';
|
||||
import WheelColorPicker from 'react-native-wheel-color-picker';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
|
||||
type ColorPickerProps = {
|
||||
color: string;
|
||||
onColorChangeComplete: (color: string) => void;
|
||||
};
|
||||
|
||||
const defaultPalette = [
|
||||
tw.color('blue-500'),
|
||||
tw.color('red-500'),
|
||||
tw.color('green-500'),
|
||||
tw.color('yellow-500'),
|
||||
tw.color('purple-500'),
|
||||
tw.color('pink-500'),
|
||||
tw.color('gray-500'),
|
||||
tw.color('black'),
|
||||
tw.color('white')
|
||||
];
|
||||
|
||||
const ColorPicker = ({ color, onColorChangeComplete }: ColorPickerProps) => {
|
||||
return (
|
||||
<WheelColorPicker
|
||||
autoResetSlider
|
||||
gapSize={0}
|
||||
thumbSize={40}
|
||||
sliderSize={24}
|
||||
shadeSliderThumb
|
||||
color={color}
|
||||
onColorChangeComplete={onColorChangeComplete}
|
||||
swatchesLast={false}
|
||||
palette={defaultPalette as string[]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColorPicker;
|
|
@ -31,7 +31,7 @@ const ModalHandle = (props: ModalHandle) => (
|
|||
>
|
||||
{props.showCloseButton && (
|
||||
<Pressable
|
||||
onPress={() => props.modalRef.current.close()}
|
||||
onPress={() => props.modalRef.current?.close()}
|
||||
style={tw`bg-app-button absolute top-5 right-4 h-7 w-7 items-center justify-center rounded-full`}
|
||||
>
|
||||
<X size={16} color="white" weight="bold" />
|
||||
|
@ -101,7 +101,7 @@ export const ConfirmModal = forwardRef<ModalRef, ConfirmModalProps>((props, ref)
|
|||
return (
|
||||
<>
|
||||
{props.trigger && (
|
||||
<Pressable onPress={() => modalRef.current.present()}>{props.trigger}</Pressable>
|
||||
<Pressable onPress={() => modalRef.current?.present()}>{props.trigger}</Pressable>
|
||||
)}
|
||||
<BottomSheetModal
|
||||
ref={modalRef}
|
||||
|
@ -126,7 +126,7 @@ export const ConfirmModal = forwardRef<ModalRef, ConfirmModalProps>((props, ref)
|
|||
style={tw`flex-1`}
|
||||
size="lg"
|
||||
disabled={props.loading} // Disables Close button if loading
|
||||
onPress={() => modalRef.current.close()}
|
||||
onPress={() => modalRef.current?.close()}
|
||||
>
|
||||
<Text style={tw`text-ink text-sm font-medium`}>Close</Text>
|
||||
</Button>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { PropsWithChildren } from 'react';
|
||||
import { FlatList } from 'react-native';
|
||||
|
||||
export default function VirtualizedListWrapper({ children }) {
|
||||
export default function VirtualizedListWrapper({ children }: PropsWithChildren) {
|
||||
return (
|
||||
<FlatList
|
||||
data={[]}
|
||||
|
|
|
@ -13,11 +13,13 @@ const sortOptions = {
|
|||
date_last_opened: 'Date Last Opened'
|
||||
};
|
||||
|
||||
type SortByType = keyof typeof sortOptions;
|
||||
|
||||
const ArrowUpIcon = () => <ArrowUp weight="bold" size={16} color={tw.color('ink')} />;
|
||||
const ArrowDownIcon = () => <ArrowDown weight="bold" size={16} color={tw.color('ink')} />;
|
||||
|
||||
const SortByMenu = () => {
|
||||
const [sortBy, setSortBy] = useState('name');
|
||||
const [sortBy, setSortBy] = useState<SortByType>('name');
|
||||
const [sortDirection, setSortDirection] = useState('asc' as 'asc' | 'desc');
|
||||
|
||||
return (
|
||||
|
@ -32,7 +34,9 @@ const SortByMenu = () => {
|
|||
{Object.entries(sortOptions).map(([value, text]) => (
|
||||
<MenuItem
|
||||
key={value}
|
||||
icon={value === sortBy && (sortDirection === 'asc' ? ArrowUpIcon : ArrowDownIcon)}
|
||||
icon={
|
||||
value === sortBy ? (sortDirection === 'asc' ? ArrowUpIcon : ArrowDownIcon) : undefined
|
||||
}
|
||||
text={text}
|
||||
value={value}
|
||||
onSelect={() => {
|
||||
|
@ -42,7 +46,7 @@ const SortByMenu = () => {
|
|||
}
|
||||
// Reset sort direction to descending
|
||||
sortDirection === 'asc' && setSortDirection('desc');
|
||||
setSortBy(value);
|
||||
setSortBy(value as SortByType);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import * as ML from 'expo-media-library';
|
||||
import { forwardRef, useCallback } from 'react';
|
||||
import { Alert, Platform, Text, View } from 'react-native';
|
||||
import { Alert, Text, View } from 'react-native';
|
||||
import DocumentPicker from 'react-native-document-picker';
|
||||
import { useLibraryMutation } from '@sd/client';
|
||||
// import RFS from 'react-native-fs';
|
||||
import { Modal, ModalRef } from '~/components/layout/Modal';
|
||||
import { Button } from '~/components/primitive/Button';
|
||||
import useForwardedRef from '~/hooks/useForwardedRef';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
|
||||
// import RFS from 'react-native-fs';
|
||||
// import * as ML from 'expo-media-library';
|
||||
|
||||
// WIP component
|
||||
const ImportModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
||||
const modalRef = useForwardedRef(ref);
|
||||
|
@ -29,6 +30,8 @@ const ImportModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
presentationStyle: 'pageSheet'
|
||||
});
|
||||
|
||||
if (!response) return;
|
||||
|
||||
createLocation({
|
||||
path: decodeURIComponent(response.uri.replace('file://', '')),
|
||||
indexer_rules_ids: []
|
||||
|
@ -43,70 +46,70 @@ const ImportModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
Alert.alert('TODO');
|
||||
return;
|
||||
|
||||
// Check if we have full access to the photos library
|
||||
let permission = await ML.getPermissionsAsync();
|
||||
// {"accessPrivileges": "none", "canAskAgain": true, "expires": "never", "granted": false, "status": "undetermined"}
|
||||
// // Check if we have full access to the photos library
|
||||
// let permission = await ML.getPermissionsAsync();
|
||||
// // {"accessPrivileges": "none", "canAskAgain": true, "expires": "never", "granted": false, "status": "undetermined"}
|
||||
|
||||
if (
|
||||
permission.status === ML.PermissionStatus.UNDETERMINED ||
|
||||
(permission.status === ML.PermissionStatus.DENIED && permission.canAskAgain)
|
||||
) {
|
||||
permission = await ML.requestPermissionsAsync();
|
||||
}
|
||||
// if (
|
||||
// permission.status === ML.PermissionStatus.UNDETERMINED ||
|
||||
// (permission.status === ML.PermissionStatus.DENIED && permission.canAskAgain)
|
||||
// ) {
|
||||
// permission = await ML.requestPermissionsAsync();
|
||||
// }
|
||||
|
||||
// Permission Denied
|
||||
if (permission.status === ML.PermissionStatus.DENIED) {
|
||||
Alert.alert(
|
||||
'Permission required',
|
||||
'You need to grant access to your photos library to import your photos/videos.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
// // Permission Denied
|
||||
// if (permission.status === ML.PermissionStatus.DENIED) {
|
||||
// Alert.alert(
|
||||
// 'Permission required',
|
||||
// 'You need to grant access to your photos library to import your photos/videos.'
|
||||
// );
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Limited Permission (Can't access path)
|
||||
if (permission.accessPrivileges === 'limited') {
|
||||
Alert.alert(
|
||||
'Limited access',
|
||||
'You need to grant full access to your photos library to import your photos/videos.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
// // Limited Permission (Can't access path)
|
||||
// if (permission.accessPrivileges === 'limited') {
|
||||
// Alert.alert(
|
||||
// 'Limited access',
|
||||
// 'You need to grant full access to your photos library to import your photos/videos.'
|
||||
// );
|
||||
// return;
|
||||
// }
|
||||
|
||||
// If android return error for now...
|
||||
if (Platform.OS !== 'ios') {
|
||||
Alert.alert('Not supported', 'Not supported for now...');
|
||||
return;
|
||||
}
|
||||
// // If android return error for now...
|
||||
// if (Platform.OS !== 'ios') {
|
||||
// Alert.alert('Not supported', 'Not supported for now...');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// And for IOS we are assuming every asset is under the same path (which is not the case)
|
||||
// // And for IOS we are assuming every asset is under the same path (which is not the case)
|
||||
|
||||
// file:///Users/xxxx/Library/Developer/CoreSimulator/Devices/F99C471F-C9F9-458D-8B87-BCC4B46C644C/data/Media/DCIM/100APPLE/IMG_0004.JPG
|
||||
// file:///var/mobile/Media/DCIM/108APPLE/IMG_8332.JPG‘
|
||||
// // file:///Users/xxxx/Library/Developer/CoreSimulator/Devices/F99C471F-C9F9-458D-8B87-BCC4B46C644C/data/Media/DCIM/100APPLE/IMG_0004.JPG
|
||||
// // file:///var/mobile/Media/DCIM/108APPLE/IMG_8332.JPG‘
|
||||
|
||||
const firstAsset = (await ML.getAssetsAsync({ first: 1 })).assets[0];
|
||||
// const firstAsset = (await ML.getAssetsAsync({ first: 1 })).assets[0];
|
||||
|
||||
if (!firstAsset) return;
|
||||
// if (!firstAsset) return;
|
||||
|
||||
// Gets asset uri: ph://CC95F08C-88C3-4012-9D6D-64A413D254B3
|
||||
const assetId = firstAsset.id;
|
||||
// Gets Actual Path
|
||||
const path = (await ML.getAssetInfoAsync(assetId)).localUri;
|
||||
// // Gets asset uri: ph://CC95F08C-88C3-4012-9D6D-64A413D254B3
|
||||
// const assetId = firstAsset?.id;
|
||||
// // Gets Actual Path
|
||||
// const path = (await ML.getAssetInfoAsync(assetId)).localUri;
|
||||
|
||||
const libraryPath = Platform.select({
|
||||
android: '',
|
||||
ios: path.replace('file://', '').split('Media/DCIM/')[0] + 'Media/DCIM/'
|
||||
});
|
||||
// const libraryPath = Platform.select({
|
||||
// android: '',
|
||||
// ios: path.replace('file://', '').split('Media/DCIM/')[0] + 'Media/DCIM/'
|
||||
// });
|
||||
|
||||
createLocation({
|
||||
path: libraryPath,
|
||||
indexer_rules_ids: []
|
||||
});
|
||||
// createLocation({
|
||||
// path: libraryPath,
|
||||
// indexer_rules_ids: []
|
||||
// });
|
||||
|
||||
// const assets = await ML.getAssetsAsync({ mediaType: ML.MediaType.photo });
|
||||
// assets.assets.map(async (i) => {
|
||||
// console.log((await ML.getAssetInfoAsync(i)).localUri);
|
||||
// });
|
||||
}, [createLocation]);
|
||||
}, []);
|
||||
|
||||
// const testFN = useCallback(async () => {
|
||||
// console.log(RFS.PicturesDirectoryPath);
|
||||
|
|
|
@ -9,7 +9,7 @@ type Props = {
|
|||
};
|
||||
|
||||
const DeleteLibraryModal = ({ trigger, onSubmit, libraryUuid }: Props) => {
|
||||
const modalRef = useRef<ModalRef>();
|
||||
const modalRef = useRef<ModalRef>(null);
|
||||
|
||||
const { mutate: deleteLibrary, isLoading: deleteLibLoading } = useBridgeMutation(
|
||||
'library.delete',
|
||||
|
@ -19,12 +19,13 @@ const DeleteLibraryModal = ({ trigger, onSubmit, libraryUuid }: Props) => {
|
|||
onSubmit?.();
|
||||
},
|
||||
onSettled: () => {
|
||||
modalRef.current.close();
|
||||
modalRef.current?.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
return (
|
||||
<ConfirmModal
|
||||
ref={modalRef}
|
||||
title="Delete Library"
|
||||
description="Deleting a library will permanently the database, the files themselves will not be deleted."
|
||||
ctaLabel="Delete"
|
||||
|
|
|
@ -9,7 +9,7 @@ type Props = {
|
|||
};
|
||||
|
||||
const DeleteLocationModal = ({ trigger, onSubmit, locationId }: Props) => {
|
||||
const modalRef = useRef<ModalRef>();
|
||||
const modalRef = useRef<ModalRef>(null);
|
||||
|
||||
const { mutate: deleteLoc, isLoading: deleteLocLoading } = useLibraryMutation(
|
||||
'locations.delete',
|
||||
|
@ -18,7 +18,7 @@ const DeleteLocationModal = ({ trigger, onSubmit, locationId }: Props) => {
|
|||
onSubmit?.();
|
||||
},
|
||||
onSettled: () => {
|
||||
modalRef.current.close();
|
||||
modalRef.current?.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -9,19 +9,20 @@ type Props = {
|
|||
};
|
||||
|
||||
const DeleteTagModal = ({ trigger, onSubmit, tagId }: Props) => {
|
||||
const modalRef = useRef<ModalRef>();
|
||||
const modalRef = useRef<ModalRef>(null);
|
||||
|
||||
const { mutate: deleteTag, isLoading: deleteTagLoading } = useLibraryMutation('tags.delete', {
|
||||
onSuccess: () => {
|
||||
onSubmit?.();
|
||||
},
|
||||
onSettled: () => {
|
||||
modalRef.current.close();
|
||||
modalRef.current?.close();
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<ConfirmModal
|
||||
ref={modalRef}
|
||||
title="Delete Tag"
|
||||
description="Are you sure you want to delete this tag? This cannot be undone and tagged files will be unlinked."
|
||||
ctaLabel="Delete"
|
||||
|
|
|
@ -71,14 +71,14 @@ export const ActionsModal = () => {
|
|||
<View style={tw`flex-1 px-4`}>
|
||||
<View style={tw`flex flex-row items-center`}>
|
||||
{/* Thumbnail/Icon */}
|
||||
<Pressable onPress={() => fileInfoRef.current.present()}>
|
||||
<Pressable onPress={() => fileInfoRef.current?.present()}>
|
||||
<FileThumb data={data} size={1} />
|
||||
</Pressable>
|
||||
<View style={tw`ml-2 flex-1`}>
|
||||
{/* Name + Extension */}
|
||||
<Text style={tw`text-base font-bold text-gray-200`} numberOfLines={1}>
|
||||
{item.name}
|
||||
{item.extension && `.${item.extension}`}
|
||||
{item?.name}
|
||||
{item?.extension && `.${item?.extension}`}
|
||||
</Text>
|
||||
<View style={tw`flex flex-row`}>
|
||||
<Text style={tw`text-ink-faint text-xs`}>
|
||||
|
@ -86,12 +86,12 @@ export const ActionsModal = () => {
|
|||
</Text>
|
||||
<Text style={tw`text-ink-faint text-xs`}>
|
||||
{' '}
|
||||
{dayjs(item.date_created).format('MMM Do YYYY')}
|
||||
{dayjs(item?.date_created).format('MMM Do YYYY')}
|
||||
</Text>
|
||||
</View>
|
||||
<InfoTagPills data={data} />
|
||||
</View>
|
||||
<FavoriteButton style={tw`mr-4`} data={objectData} />
|
||||
{objectData && <FavoriteButton style={tw`mr-4`} data={objectData} />}
|
||||
</View>
|
||||
<View style={tw`my-3`} />
|
||||
{/* Actions */}
|
||||
|
@ -99,7 +99,7 @@ export const ActionsModal = () => {
|
|||
<ActionsItem
|
||||
icon={Info}
|
||||
title="Show Info"
|
||||
onPress={() => fileInfoRef.current.present()}
|
||||
onPress={() => fileInfoRef.current?.present()}
|
||||
/>
|
||||
</ActionsContainer>
|
||||
<ActionsContainer style={tw`mt-2`}>
|
||||
|
|
|
@ -31,7 +31,7 @@ function MetaItem({ title, value, icon }: MetaItemProps) {
|
|||
<>
|
||||
<View style={tw`flex flex-row items-center`}>
|
||||
<View style={tw`w-30 flex flex-row items-center`}>
|
||||
{icon && <Icon color="white" size={18} style={tw`mr-1`} />}
|
||||
{Icon && <Icon color="white" size={18} style={tw`mr-1`} />}
|
||||
<Text style={tw`text-sm font-medium text-white`}>{title}</Text>
|
||||
</View>
|
||||
<Text style={tw`text-sm text-gray-400`}>{value}</Text>
|
||||
|
@ -42,7 +42,7 @@ function MetaItem({ title, value, icon }: MetaItemProps) {
|
|||
}
|
||||
|
||||
type FileInfoModalProps = {
|
||||
data: ExplorerItem;
|
||||
data: ExplorerItem | null;
|
||||
};
|
||||
|
||||
const FileInfoModal = forwardRef<ModalRef, FileInfoModalProps>((props, ref) => {
|
||||
|
@ -69,13 +69,13 @@ const FileInfoModal = forwardRef<ModalRef, FileInfoModalProps>((props, ref) => {
|
|||
{data && (
|
||||
<ModalScrollView style={tw`flex-1 p-4`}>
|
||||
{/* Back Button */}
|
||||
<Pressable onPress={() => modalRef.current.close()} style={tw`absolute z-10 ml-4`}>
|
||||
<Pressable onPress={() => modalRef.current?.close()} style={tw`absolute z-10 ml-4`}>
|
||||
<CaretLeft color={tw.color('accent')} size={20} weight="bold" />
|
||||
</Pressable>
|
||||
{/* File Icon / Name */}
|
||||
<View style={tw`items-center`}>
|
||||
<FileThumb data={data} size={1.6} />
|
||||
<Text style={tw`mt-2 text-base font-bold text-gray-200`}>{item.name}</Text>
|
||||
<Text style={tw`mt-2 text-base font-bold text-gray-200`}>{item?.name}</Text>
|
||||
<InfoTagPills data={data} style={tw`mt-3`} />
|
||||
</View>
|
||||
{/* Details */}
|
||||
|
@ -99,19 +99,21 @@ const FileInfoModal = forwardRef<ModalRef, FileInfoModalProps>((props, ref) => {
|
|||
<MetaItem
|
||||
icon={Clock}
|
||||
title="Created"
|
||||
value={dayjs(item.date_created).format('MMM Do YYYY')}
|
||||
value={dayjs(item?.date_created).format('MMM Do YYYY')}
|
||||
/>
|
||||
{/* Indexed */}
|
||||
<MetaItem
|
||||
icon={Barcode}
|
||||
title="Indexed"
|
||||
value={dayjs(item.date_indexed).format('MMM Do YYYY')}
|
||||
value={dayjs(item?.date_indexed).format('MMM Do YYYY')}
|
||||
/>
|
||||
|
||||
{filePathData && (
|
||||
<>
|
||||
{/* TODO: Note */}
|
||||
{filePathData.cas_id && (
|
||||
<MetaItem icon={Snowflake} title="Content ID" value={filePathData.cas_id} />
|
||||
)}
|
||||
{/* Checksum */}
|
||||
{filePathData?.integrity_checksum && (
|
||||
<MetaItem
|
||||
|
|
|
@ -3,9 +3,9 @@ import { Pressable, Text, View } from 'react-native';
|
|||
import ColorPicker from 'react-native-wheel-color-picker';
|
||||
import { queryClient, useLibraryMutation } from '@sd/client';
|
||||
import { FadeInAnimation } from '~/components/animation/layout';
|
||||
import { Input } from '~/components/form/Input';
|
||||
import { Modal, ModalRef } from '~/components/layout/Modal';
|
||||
import { Button } from '~/components/primitive/Button';
|
||||
import { Input } from '~/components/primitive/Input';
|
||||
import useForwardedRef from '~/hooks/useForwardedRef';
|
||||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
|
||||
|
@ -29,12 +29,12 @@ const CreateTagModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
},
|
||||
onSettled: () => {
|
||||
// Close modal
|
||||
modalRef.current.dismiss();
|
||||
modalRef.current?.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
modalRef.current.snapToIndex(showPicker ? 1 : 0);
|
||||
modalRef.current?.snapToIndex(showPicker ? 1 : 0);
|
||||
}, [modalRef, showPicker]);
|
||||
|
||||
return (
|
||||
|
@ -70,27 +70,7 @@ const CreateTagModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
{showPicker && (
|
||||
<FadeInAnimation>
|
||||
<View style={tw`mt-4 h-64`}>
|
||||
<ColorPicker
|
||||
autoResetSlider
|
||||
gapSize={0}
|
||||
thumbSize={40}
|
||||
sliderSize={24}
|
||||
shadeSliderThumb
|
||||
color={tagColor}
|
||||
onColorChangeComplete={(color) => setTagColor(color)}
|
||||
swatchesLast={false}
|
||||
palette={[
|
||||
tw.color('blue-500'),
|
||||
tw.color('red-500'),
|
||||
tw.color('green-500'),
|
||||
tw.color('yellow-500'),
|
||||
tw.color('purple-500'),
|
||||
tw.color('pink-500'),
|
||||
tw.color('gray-500'),
|
||||
tw.color('black'),
|
||||
tw.color('white')
|
||||
]}
|
||||
/>
|
||||
<ColorPicker color={tagColor} onColorChangeComplete={(color) => setTagColor(color)} />
|
||||
</View>
|
||||
</FadeInAnimation>
|
||||
)}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { forwardRef, useEffect, useState } from 'react';
|
||||
import { Pressable, Text, View } from 'react-native';
|
||||
import ColorPicker from 'react-native-wheel-color-picker';
|
||||
import { ColorValue, Pressable, Text, View } from 'react-native';
|
||||
import { Tag, queryClient, useLibraryMutation } from '@sd/client';
|
||||
import { FadeInAnimation } from '~/components/animation/layout';
|
||||
import ColorPicker from '~/components/form/ColorPicker';
|
||||
import { Input } from '~/components/form/Input';
|
||||
import { Modal, ModalRef } from '~/components/layout/Modal';
|
||||
import { Button } from '~/components/primitive/Button';
|
||||
import { Input } from '~/components/primitive/Input';
|
||||
import useForwardedRef from '~/hooks/useForwardedRef';
|
||||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
|
||||
|
@ -17,8 +17,8 @@ type Props = {
|
|||
const UpdateTagModal = forwardRef<ModalRef, Props>((props, ref) => {
|
||||
const modalRef = useForwardedRef(ref);
|
||||
|
||||
const [tagName, setTagName] = useState(props.tag.name);
|
||||
const [tagColor, setTagColor] = useState(props.tag.color);
|
||||
const [tagName, setTagName] = useState(props.tag.name!);
|
||||
const [tagColor, setTagColor] = useState(props.tag.color!);
|
||||
const [showPicker, setShowPicker] = useState(false);
|
||||
|
||||
const { mutate: updateTag, isLoading } = useLibraryMutation('tags.update', {
|
||||
|
@ -31,12 +31,12 @@ const UpdateTagModal = forwardRef<ModalRef, Props>((props, ref) => {
|
|||
props.onSubmit?.();
|
||||
},
|
||||
onSettled: () => {
|
||||
modalRef.current.dismiss();
|
||||
modalRef.current?.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
modalRef.current.snapToIndex(showPicker ? 1 : 0);
|
||||
modalRef.current?.snapToIndex(showPicker ? 1 : 0);
|
||||
}, [modalRef, showPicker]);
|
||||
|
||||
return (
|
||||
|
@ -63,32 +63,12 @@ const UpdateTagModal = forwardRef<ModalRef, Props>((props, ref) => {
|
|||
style={twStyle({ backgroundColor: tagColor }, 'h-5 w-5 rounded-full')}
|
||||
/>
|
||||
{/* TODO: Make this editable. Need to make sure color is a valid hexcode and update the color on picker etc. etc. */}
|
||||
<Input editable={false} value={tagColor} style={tw`ml-2 flex-1`} />
|
||||
<Input editable={false} value={tagColor as string} style={tw`ml-2 flex-1`} />
|
||||
</View>
|
||||
{showPicker && (
|
||||
<FadeInAnimation>
|
||||
<View style={tw`mt-4 h-64`}>
|
||||
<ColorPicker
|
||||
autoResetSlider
|
||||
gapSize={0}
|
||||
thumbSize={40}
|
||||
sliderSize={24}
|
||||
shadeSliderThumb
|
||||
color={tagColor}
|
||||
onColorChangeComplete={(color) => setTagColor(color)}
|
||||
swatchesLast={false}
|
||||
palette={[
|
||||
tw.color('blue-500'),
|
||||
tw.color('red-500'),
|
||||
tw.color('green-500'),
|
||||
tw.color('yellow-500'),
|
||||
tw.color('purple-500'),
|
||||
tw.color('pink-500'),
|
||||
tw.color('gray-500'),
|
||||
tw.color('black'),
|
||||
tw.color('white')
|
||||
]}
|
||||
/>
|
||||
<ColorPicker color={tagColor} onColorChangeComplete={(color) => setTagColor(color)} />
|
||||
</View>
|
||||
</FadeInAnimation>
|
||||
)}
|
||||
|
|
|
@ -79,7 +79,7 @@ export function createReactNativeClient(): TRPCWebSocketClient {
|
|||
body = JSON.stringify(outgoing);
|
||||
}
|
||||
|
||||
SDCore.sd_core_msg(body).then((rawData) => {
|
||||
SDCore.sd_core_msg(body).then((rawData: string) => {
|
||||
const data = JSON.parse(rawData);
|
||||
if (Array.isArray(data)) {
|
||||
for (const payload of data) {
|
||||
|
|
|
@ -58,7 +58,7 @@ if (Platform.OS === 'ios') {
|
|||
const App = lazy(async () => {
|
||||
const keys = await AsyncStorage.getAllKeys();
|
||||
const values = await AsyncStorage.multiGet(keys);
|
||||
values.forEach(([key, value]) => _localStorage.set(key, value));
|
||||
values.forEach(([key, value]) => _localStorage.set(key, value!));
|
||||
|
||||
return await import('./App');
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ export default function LocationScreen({ navigation, route }: SharedScreenProps<
|
|||
'locations.getExplorerData',
|
||||
{
|
||||
location_id: id,
|
||||
path: path || '',
|
||||
path: path ?? '',
|
||||
limit: 100,
|
||||
cursor: null
|
||||
}
|
||||
|
@ -26,14 +26,14 @@ export default function LocationScreen({ navigation, route }: SharedScreenProps<
|
|||
});
|
||||
} else {
|
||||
navigation.setOptions({
|
||||
title: data?.context.name
|
||||
title: data?.context.name ?? 'Location'
|
||||
});
|
||||
}
|
||||
}, [data, navigation, path]);
|
||||
|
||||
useEffect(() => {
|
||||
getExplorerStore().locationId = id;
|
||||
getExplorerStore().path = path;
|
||||
getExplorerStore().path = path ?? '';
|
||||
}, [id, path]);
|
||||
|
||||
return <Explorer data={data} />;
|
||||
|
|
|
@ -6,7 +6,15 @@ export default function NotFoundScreen({ navigation }: RootStackScreenProps<'Not
|
|||
return (
|
||||
<View style={tw`flex-1 items-center justify-center p-5`}>
|
||||
<Text style={tw`text-xl font-bold`}>This screen doesn't exist.</Text>
|
||||
<TouchableOpacity onPress={() => navigation.replace('Root')} style={tw`mt-4 py-4`}>
|
||||
<TouchableOpacity
|
||||
onPress={() =>
|
||||
navigation.replace('Root', {
|
||||
screen: 'Home',
|
||||
params: { screen: 'OverviewStack', params: { screen: 'Overview' } }
|
||||
})
|
||||
}
|
||||
style={tw`mt-4 py-4`}
|
||||
>
|
||||
<Text style={tw`text-ink-dull text-sm`}>Go to home screen!</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
|
|
@ -12,7 +12,7 @@ export default function TagScreen({ navigation, route }: SharedScreenProps<'Tag'
|
|||
useEffect(() => {
|
||||
// Set screen title to tag name.
|
||||
navigation.setOptions({
|
||||
title: data?.context.name
|
||||
title: data?.context.name ?? 'Tag'
|
||||
});
|
||||
}, [data?.context.name, navigation]);
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { useBridgeQuery } from '@sd/client';
|
||||
import { Input } from '~/components/form/Input';
|
||||
import Card from '~/components/layout/Card';
|
||||
import Divider from '~/components/primitive/Divider';
|
||||
import { Input } from '~/components/primitive/Input';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { SettingsStackScreenProps } from '~/navigation/SettingsNavigator';
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ import React from 'react';
|
|||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { Alert, Text, View } from 'react-native';
|
||||
import { useBridgeMutation, useLibraryContext } from '@sd/client';
|
||||
import { Input } from '~/components/form/Input';
|
||||
import { Switch } from '~/components/form/Switch';
|
||||
import { Button } from '~/components/primitive/Button';
|
||||
import { Input } from '~/components/primitive/Input';
|
||||
import { Switch } from '~/components/primitive/Switch';
|
||||
import { SettingsContainer } from '~/components/settings/SettingsContainer';
|
||||
import { SettingsItem } from '~/components/settings/SettingsItem';
|
||||
import { useAutoForm } from '~/hooks/useAutoForm';
|
||||
|
|
|
@ -11,7 +11,7 @@ import { tw, twStyle } from '~/lib/tailwind';
|
|||
import { SettingsStackScreenProps } from '~/navigation/SettingsNavigator';
|
||||
|
||||
function TagItem({ tag, index }: { tag: Tag; index: number }) {
|
||||
const updateTagModalRef = useRef<ModalRef>();
|
||||
const updateTagModalRef = useRef<ModalRef>(null);
|
||||
|
||||
const renderRightActions = (
|
||||
progress: Animated.AnimatedInterpolation<number>,
|
||||
|
@ -29,7 +29,7 @@ function TagItem({ tag, index }: { tag: Tag; index: number }) {
|
|||
style={[tw`flex flex-row items-center`, { transform: [{ translateX: translate }] }]}
|
||||
>
|
||||
<UpdateTagModal tag={tag} ref={updateTagModalRef} onSubmit={() => swipeable.close()} />
|
||||
<AnimatedButton size="md" onPress={() => updateTagModalRef.current.present()}>
|
||||
<AnimatedButton size="md" onPress={() => updateTagModalRef.current?.present()}>
|
||||
<Pen size={18} color="white" />
|
||||
</AnimatedButton>
|
||||
<DeleteTagModal
|
||||
|
@ -55,7 +55,7 @@ function TagItem({ tag, index }: { tag: Tag; index: number }) {
|
|||
>
|
||||
<View style={tw`flex flex-row items-center justify-between`}>
|
||||
<View style={tw`flex flex-row`}>
|
||||
<View style={twStyle({ backgroundColor: tag.color }, 'h-4 w-4 rounded-full')} />
|
||||
<View style={twStyle({ backgroundColor: tag.color! }, 'h-4 w-4 rounded-full')} />
|
||||
<Text style={tw`text-ink ml-3`}>{tag.name}</Text>
|
||||
</View>
|
||||
<CaretRight color={tw.color('ink-dull')} size={18} />
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
DrawerNavigationState,
|
||||
ParamListBase,
|
||||
Route,
|
||||
getFocusedRouteNameFromRoute
|
||||
} from '@react-navigation/native';
|
||||
import { valtioPersist } from '@sd/client';
|
||||
|
@ -9,7 +10,9 @@ export const currentLibraryStore = valtioPersist('sdActiveLibrary', {
|
|||
id: null as string | null
|
||||
});
|
||||
|
||||
export const getActiveRouteFromState = function (state: any) {
|
||||
export const getActiveRouteFromState = function (
|
||||
state: any
|
||||
): Partial<Route<string, object | undefined>> {
|
||||
if (!state.routes || state.routes.length === 0 || state.index >= state.routes.length) {
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
{
|
||||
"extends": "expo/tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "react-native",
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"noEmit": true,
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
},
|
||||
"jsx": "react-native"
|
||||
"strict": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"exclude": ["node_modules", "babel.config.js", "metro.config.js", "jest.config.js"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../packages/client"
|
||||
|
|
|
@ -2,25 +2,21 @@
|
|||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Default",
|
||||
"compilerOptions": {
|
||||
// Actual type stuff
|
||||
"strict": true,
|
||||
"jsx": "react-jsx",
|
||||
"esModuleInterop": true,
|
||||
// Various configs
|
||||
"skipLibCheck": true,
|
||||
"preserveWatchOutput": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
// Project references stuff
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"composite": true,
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
// Module stuff
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"module": "ESNext",
|
||||
"target": "ESNext",
|
||||
// Extra types
|
||||
"types": ["vite-plugin-svgr/client", "vite/client"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ function Index() {
|
|||
|
||||
const currentLibrary = libraries.data.find((l) => l.uuid === currentLibraryCache.id);
|
||||
|
||||
const libraryId = currentLibrary ? currentLibrary.uuid : libraries.data[0].uuid;
|
||||
const libraryId = currentLibrary ? currentLibrary.uuid : libraries.data[0]?.uuid;
|
||||
|
||||
return <Navigate to={`${libraryId}/overview`} />;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ export const EncryptFileDialog = ({ ...props }: EncryptDialogProps) => {
|
|||
const keys = useLibraryQuery(['keys.list']);
|
||||
const mountedUuids = useLibraryQuery(['keys.listMounted'], {
|
||||
onSuccess: (data) => {
|
||||
UpdateKey(data[0]);
|
||||
UpdateKey(data[0] ?? '');
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -56,9 +56,9 @@ export const EraseFileDialog = (props: EraseDialogProps) => {
|
|||
min={1}
|
||||
step={1}
|
||||
defaultValue={[4]}
|
||||
onValueChange={(e) => {
|
||||
setPasses(e);
|
||||
form.setValue('passes', e[0]);
|
||||
onValueChange={(val) => {
|
||||
setPasses(val);
|
||||
form.setValue('passes', val[0] ?? 1);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -41,7 +41,7 @@ export const KeyViewerDialog = (props: KeyViewerDialogProps) => {
|
|||
const keys = useLibraryQuery(['keys.list'], {
|
||||
onSuccess: (data) => {
|
||||
if (key === '' && data.length !== 0) {
|
||||
setKey(data[0].uuid);
|
||||
setKey(data[0]?.uuid ?? '');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -145,7 +145,7 @@ export const VirtualizedList = memo(({ data, context, onScroll }: Props) => {
|
|||
kind="list"
|
||||
isSelected={getExplorerStore().selectedRowIndex === virtualRow.index}
|
||||
index={virtualRow.index}
|
||||
item={data[virtualRow.index]}
|
||||
item={data[virtualRow.index]!}
|
||||
/>
|
||||
) : (
|
||||
[...Array(amountOfColumns)].map((_, i) => {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import cryptoRandomString from 'crypto-random-string';
|
||||
import { Eye, EyeSlash, Info } from 'phosphor-react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Algorithm, useLibraryMutation, useLibraryQuery } from '@sd/client';
|
||||
import { Button, CategoryHeading, Input, Select, SelectOption, Switch, cva, tw } from '@sd/ui';
|
||||
import { Algorithm, useLibraryMutation } from '@sd/client';
|
||||
import { Button, CategoryHeading, Input, Select, SelectOption, Switch, tw } from '@sd/ui';
|
||||
import { getHashingAlgorithmSettings } from '../../screens/settings/library/KeysSetting';
|
||||
import Slider from '../primitive/Slider';
|
||||
import { Tooltip } from '../tooltip/Tooltip';
|
||||
|
@ -67,12 +67,12 @@ export function KeyMounter() {
|
|||
min={8}
|
||||
step={4}
|
||||
defaultValue={[64]}
|
||||
onValueChange={(e) => {
|
||||
setSliderValue(e);
|
||||
setKey(generatePassword(e[0]));
|
||||
onValueChange={(val) => {
|
||||
setSliderValue(val);
|
||||
setKey(generatePassword(val[0] ?? 8));
|
||||
}}
|
||||
onClick={() => {
|
||||
setKey(generatePassword(sliderValue[0]));
|
||||
setKey(generatePassword(sliderValue[0] ?? 8));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ export const useCurrentOnboardingScreenKey = (): string | null => {
|
|||
const { pathname } = useLocation();
|
||||
|
||||
if (pathname.startsWith(`/${ONBOARDING_ROUTE_PREFIX_NAME}/`)) {
|
||||
return pathname.split('/')[2];
|
||||
return pathname.split('/')[2] || null;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -18,9 +18,9 @@ export function MacTrafficLights(props: TrafficLightsProps) {
|
|||
|
||||
return (
|
||||
<div data-tauri-drag-region className={clsx('group flex flex-row space-x-[7.5px]', className)}>
|
||||
<TrafficLight type="close" onClick={onClose} colorful={focused} />
|
||||
<TrafficLight type="minimize" onClick={onMinimize} colorful={focused} />
|
||||
<TrafficLight type="fullscreen" onClick={onFullscreen} colorful={focused} />
|
||||
<TrafficLight type="close" onClick={onClose} colorful={focused ?? false} />
|
||||
<TrafficLight type="minimize" onClick={onMinimize} colorful={focused ?? false} />
|
||||
<TrafficLight type="fullscreen" onClick={onFullscreen} colorful={focused ?? false} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -312,7 +312,7 @@ const table: Record<string, HashingAlgorithm> = {
|
|||
|
||||
// not sure of a suitable place for this function
|
||||
export const getHashingAlgorithmSettings = (hashingAlgorithm: string): HashingAlgorithm => {
|
||||
return table[hashingAlgorithm];
|
||||
return table[hashingAlgorithm] || { name: 'Argon2id', params: 'Standard' };
|
||||
};
|
||||
|
||||
// not sure of a suitable place for this function
|
||||
|
|
Loading…
Reference in a new issue