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