linked-data-browser 0.0.7 → 0.0.8-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +2 -0
- package/.eslintrc.js +1 -0
- package/app/index.tsx +3 -0
- package/babel.config.js +7 -8
- package/components/DataBrowser.tsx +9 -19
- package/components/DataBrowserContext.ts +24 -0
- package/components/TargetResourceProvider.tsx +1 -1
- package/components/ThemeProvider.tsx +2 -4
- package/components/common/LoadingBar.tsx +11 -1
- package/components/common/ProfileAvatar.tsx +4 -7
- package/components/nav/Layout.tsx +20 -4
- package/components/nav/header/AddressBox.tsx +104 -48
- package/components/nav/header/AvatarMenu.tsx +42 -10
- package/components/nav/header/Header.tsx +26 -19
- package/components/nav/header/SignInMenu.tsx +63 -36
- package/components/nav/header/ThemeToggleMenu.tsx +21 -9
- package/components/nav/header/ViewMenu.tsx +79 -71
- package/components/sharing/AccessDropdown.tsx +18 -7
- package/components/sharing/CopyLink.tsx +15 -3
- package/components/sharing/PermissionRow.tsx +17 -2
- package/components/sharing/SharingModal.tsx +30 -3
- package/components/sharing/WacRuleForm.tsx +12 -3
- package/components/sharing/agentPermissions/AgentInformation.tsx +16 -3
- package/components/sharing/agentPermissions/AgentInput.tsx +19 -4
- package/components/sharing/agentPermissions/AgentPermissionRow.tsx +24 -6
- package/components/ui/accordion.tsx +1 -1
- package/components/ui/alert.tsx +62 -46
- package/components/ui/avatar.tsx +38 -13
- package/components/ui/badge.tsx +63 -48
- package/components/ui/button.tsx +226 -108
- package/components/ui/card.tsx +53 -38
- package/components/ui/checkbox.tsx +53 -16
- package/components/ui/context-menu.tsx +4 -4
- package/components/ui/dialog.tsx +116 -65
- package/components/ui/dropdown-menu.tsx +304 -105
- package/components/ui/icon.tsx +23 -0
- package/components/ui/input-dropdown.tsx +42 -5
- package/components/ui/input.tsx +85 -22
- package/components/ui/label.tsx +16 -7
- package/components/ui/menubar.tsx +4 -4
- package/components/ui/navigation-menu.tsx +157 -90
- package/components/ui/progress.tsx +38 -24
- package/components/ui/select.tsx +139 -67
- package/components/ui/separator.tsx +22 -7
- package/components/ui/skeleton.tsx +14 -11
- package/components/ui/switch.tsx +82 -37
- package/components/ui/table.tsx +57 -35
- package/components/ui/tabs.tsx +66 -35
- package/components/ui/text.tsx +221 -30
- package/components/ui/textarea.tsx +34 -10
- package/components/ui/typography.tsx +94 -65
- package/components/useViewContext.tsx +8 -8
- package/global.css +93 -3
- package/metro.config.js +1 -3
- package/package.json +3 -7
- package/resourceViews/Container/ContainerConfig.tsx +1 -1
- package/resourceViews/Container/ContainerView.tsx +63 -25
- package/resourceViews/Profile/ProfileConfig.tsx +1 -1
- package/resourceViews/Profile/ProfileKnows.tsx +17 -9
- package/resourceViews/Profile/ProfileView.tsx +21 -4
- package/resourceViews/RawCode/RawCodeConfig.tsx +1 -1
- package/resourceViews/RawCode/RawCodeView.tsx +20 -6
- package/components.json +0 -7
- package/lib/icons/ArrowRight.tsx +0 -4
- package/lib/icons/Check.tsx +0 -4
- package/lib/icons/ChevronDown.tsx +0 -4
- package/lib/icons/ChevronRight.tsx +0 -4
- package/lib/icons/ChevronUp.tsx +0 -4
- package/lib/icons/ChevronsRight.tsx +0 -4
- package/lib/icons/CircleSlash.tsx +0 -4
- package/lib/icons/CircleX.tsx +0 -4
- package/lib/icons/Code.tsx +0 -4
- package/lib/icons/EllipsisVertical.tsx +0 -4
- package/lib/icons/EyeOff.tsx +0 -4
- package/lib/icons/File.tsx +0 -4
- package/lib/icons/Fingerprint.tsx +0 -4
- package/lib/icons/Folder.tsx +0 -4
- package/lib/icons/Folders.tsx +0 -4
- package/lib/icons/Info.tsx +0 -4
- package/lib/icons/Link.tsx +0 -4
- package/lib/icons/Loader.tsx +0 -4
- package/lib/icons/LogOut.tsx +0 -4
- package/lib/icons/MonitorSmartphone.tsx +0 -4
- package/lib/icons/MoonStar.tsx +0 -4
- package/lib/icons/OctagonX.tsx +0 -4
- package/lib/icons/Plus.tsx +0 -4
- package/lib/icons/RefreshCw.tsx +0 -4
- package/lib/icons/Save.tsx +0 -4
- package/lib/icons/ShieldX.tsx +0 -4
- package/lib/icons/Sun.tsx +0 -4
- package/lib/icons/TextCursorInput.tsx +0 -4
- package/lib/icons/Trash.tsx +0 -4
- package/lib/icons/User.tsx +0 -4
- package/lib/icons/UserPlus.tsx +0 -4
- package/lib/icons/Users.tsx +0 -4
- package/lib/icons/ViewIcon.tsx +0 -4
- package/lib/icons/X.tsx +0 -4
- package/lib/icons/iconWithClassName.ts +0 -14
- package/lib/utils.ts +0 -6
- package/nativewind-env.d.ts +0 -1
- package/tailwind.config.js +0 -69
package/.env
ADDED
package/.eslintrc.js
CHANGED
package/app/index.tsx
CHANGED
|
@@ -12,6 +12,8 @@ export function Screen() {
|
|
|
12
12
|
? 'server-ui'
|
|
13
13
|
: 'standalone-app';
|
|
14
14
|
|
|
15
|
+
const defaultIssuer = process.env.EXPO_PUBLIC_DEFAULT_ISSUER;
|
|
16
|
+
|
|
15
17
|
return (
|
|
16
18
|
<SafeAreaProvider>
|
|
17
19
|
<StatusBar />
|
|
@@ -20,6 +22,7 @@ export function Screen() {
|
|
|
20
22
|
mode={mode}
|
|
21
23
|
renderHomepage={() => <Text>Hopepage</Text>}
|
|
22
24
|
renderLogo={() => <Text>Logo</Text>}
|
|
25
|
+
defaultIssuer={defaultIssuer}
|
|
23
26
|
/>
|
|
24
27
|
</SafeAreaProvider>
|
|
25
28
|
);
|
package/babel.config.js
CHANGED
|
@@ -2,14 +2,13 @@ module.exports = function (api) {
|
|
|
2
2
|
api.cache(true);
|
|
3
3
|
return {
|
|
4
4
|
presets: [
|
|
5
|
-
[
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
[
|
|
6
|
+
'babel-preset-expo',
|
|
7
|
+
{
|
|
8
|
+
unstable_transformProfile: 'hermes-canary',
|
|
9
|
+
},
|
|
10
|
+
],
|
|
10
11
|
],
|
|
11
|
-
plugins: [
|
|
12
|
-
'@babel/plugin-syntax-import-meta'
|
|
13
|
-
]
|
|
12
|
+
plugins: ['@babel/plugin-syntax-import-meta'],
|
|
14
13
|
};
|
|
15
14
|
};
|
|
@@ -1,31 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
2
|
import { BrowserSolidLdoProvider } from '@ldo/solid-react';
|
|
3
3
|
import React, { FunctionComponent } from 'react';
|
|
4
4
|
import { Layout } from './nav/Layout';
|
|
5
5
|
import { PortalHost } from '@rn-primitives/portal';
|
|
6
6
|
import { TargetResourceProvider } from './TargetResourceProvider';
|
|
7
|
-
import { ResourceViewConfig } from './ResourceView';
|
|
8
7
|
import { NotifierWrapper } from 'react-native-notifier';
|
|
9
8
|
import { Platform } from 'react-native';
|
|
10
9
|
import { ThemeProvider } from './ThemeProvider';
|
|
10
|
+
import {
|
|
11
|
+
DataBrowserConfig,
|
|
12
|
+
DataBrowserConfigContext,
|
|
13
|
+
DataBrowserConfigProps,
|
|
14
|
+
} from './DataBrowserContext';
|
|
11
15
|
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
defaultIssuer?: string;
|
|
16
|
-
origin?: string;
|
|
17
|
-
renderHomepage?: () => ReactNode;
|
|
18
|
-
renderLogo?: () => ReactNode;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// @ts-ignore This will be filled in once the component mounts
|
|
22
|
-
export const DataBrowserConfigContext = createContext<DataBrowserConfig>({});
|
|
23
|
-
|
|
24
|
-
export function useDataBrowserConfig() {
|
|
25
|
-
return useContext(DataBrowserConfigContext);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const DataBrowser: FunctionComponent<DataBrowserConfig> = (props) => {
|
|
16
|
+
export const DataBrowser: FunctionComponent<DataBrowserConfigProps> = (
|
|
17
|
+
props,
|
|
18
|
+
) => {
|
|
29
19
|
const providerProps = useMemo<DataBrowserConfig>(() => {
|
|
30
20
|
return {
|
|
31
21
|
origin:
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createContext, ReactNode, useContext } from 'react';
|
|
2
|
+
import { ResourceViewConfig } from './ResourceView';
|
|
3
|
+
|
|
4
|
+
export interface DataBrowserConfigProps {
|
|
5
|
+
views: ResourceViewConfig[];
|
|
6
|
+
mode: 'standalone-app' | 'server-ui';
|
|
7
|
+
defaultIssuer?: string;
|
|
8
|
+
origin?: string;
|
|
9
|
+
renderHomepage?: () => ReactNode;
|
|
10
|
+
renderLogo?: () => ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface DataBrowserConfig extends DataBrowserConfigProps {
|
|
14
|
+
defaultIssuer: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const DataBrowserConfigContext = createContext<DataBrowserConfig>(
|
|
18
|
+
// @ts-ignore This will be filled in once the component mounts
|
|
19
|
+
{},
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
export function useDataBrowserConfig() {
|
|
23
|
+
return useContext(DataBrowserConfigContext);
|
|
24
|
+
}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from 'react';
|
|
8
8
|
import { SolidLeaf, SolidContainer } from '@ldo/connected-solid';
|
|
9
9
|
import { InvalidIdentifierResource } from '@ldo/connected';
|
|
10
|
-
import { useDataBrowserConfig } from './
|
|
10
|
+
import { useDataBrowserConfig } from './DataBrowserContext';
|
|
11
11
|
import { useResource } from '@ldo/solid-react';
|
|
12
12
|
import { Platform } from 'react-native';
|
|
13
13
|
|
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
Theme,
|
|
18
18
|
} from '@react-navigation/native';
|
|
19
19
|
import { NAV_THEME } from '../lib/constants';
|
|
20
|
-
import { useColorScheme } from 'nativewind';
|
|
21
20
|
import { setAndroidNavigationBar } from '../lib/android-navigation-bar';
|
|
22
21
|
|
|
23
22
|
const COLOR_SCHEME_KEY = 'colorScheme';
|
|
@@ -57,14 +56,14 @@ const usePlatformSpecificSetup = Platform.select({
|
|
|
57
56
|
export const ThemeProvider: FunctionComponent<PropsWithChildren> = ({
|
|
58
57
|
children,
|
|
59
58
|
}) => {
|
|
60
|
-
const
|
|
59
|
+
const [colorScheme, setColorScheme] = useState<ColorSchemeName>();
|
|
61
60
|
const [loadingColorScheme, setLoadingColorScheme] = useState(true);
|
|
62
61
|
|
|
63
62
|
usePlatformSpecificSetup();
|
|
64
63
|
|
|
65
64
|
useEffect(() => {
|
|
66
65
|
const lookupCurColorScheme = async () => {
|
|
67
|
-
setColorScheme(Appearance.getColorScheme() ?? '
|
|
66
|
+
setColorScheme(Appearance.getColorScheme() ?? 'light');
|
|
68
67
|
const storedColorSchemeName: ColorSchemeName =
|
|
69
68
|
((await AsyncStorage.getItem(COLOR_SCHEME_KEY)) as ColorSchemeName) ||
|
|
70
69
|
Appearance.getColorScheme();
|
|
@@ -74,7 +73,6 @@ export const ThemeProvider: FunctionComponent<PropsWithChildren> = ({
|
|
|
74
73
|
setLoadingColorScheme(false);
|
|
75
74
|
};
|
|
76
75
|
lookupCurColorScheme();
|
|
77
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
78
76
|
}, []);
|
|
79
77
|
|
|
80
78
|
const context = useMemo(
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { useTheme } from '@react-navigation/native';
|
|
3
3
|
import { FunctionComponent } from 'react';
|
|
4
4
|
import { Bar } from 'react-native-progress';
|
|
5
|
+
import { StyleSheet } from 'react-native';
|
|
5
6
|
|
|
6
7
|
interface LoadingBarProps {
|
|
7
8
|
isLoading: boolean;
|
|
@@ -21,7 +22,16 @@ export const LoadingBar: FunctionComponent<LoadingBarProps> = ({
|
|
|
21
22
|
borderWidth={0}
|
|
22
23
|
borderRadius={0}
|
|
23
24
|
width={null}
|
|
24
|
-
|
|
25
|
+
style={styles.bar}
|
|
25
26
|
/>
|
|
26
27
|
);
|
|
27
28
|
};
|
|
29
|
+
|
|
30
|
+
const styles = StyleSheet.create({
|
|
31
|
+
bar: {
|
|
32
|
+
position: 'absolute',
|
|
33
|
+
top: 0,
|
|
34
|
+
left: 0,
|
|
35
|
+
right: 0,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
@@ -2,22 +2,19 @@ import React from 'react';
|
|
|
2
2
|
import { SolidProfile } from '../../.ldo/profile.typings';
|
|
3
3
|
import { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar';
|
|
4
4
|
import { Text } from '../ui/text';
|
|
5
|
-
import { User } from '
|
|
5
|
+
import { User } from 'lucide-react-native';
|
|
6
6
|
import { FunctionComponent } from 'react';
|
|
7
7
|
|
|
8
8
|
interface ProfileAvatarProps {
|
|
9
9
|
profile?: SolidProfile;
|
|
10
|
-
|
|
10
|
+
style?: any;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export const ProfileAvatar: FunctionComponent<ProfileAvatarProps> = ({
|
|
14
14
|
profile,
|
|
15
|
-
|
|
15
|
+
style,
|
|
16
16
|
}) => (
|
|
17
|
-
<Avatar
|
|
18
|
-
alt={profile?.fn ? `${profile.fn}'s Avatar` : ''}
|
|
19
|
-
className={className}
|
|
20
|
-
>
|
|
17
|
+
<Avatar alt={profile?.fn ? `${profile.fn}'s Avatar` : ''} style={style}>
|
|
21
18
|
<AvatarImage source={{ uri: profile?.hasPhoto?.['@id'] }} />
|
|
22
19
|
<AvatarFallback>
|
|
23
20
|
<Text>
|
|
@@ -7,11 +7,12 @@ import React, {
|
|
|
7
7
|
import { ResourceViewConfig } from '../ResourceView';
|
|
8
8
|
|
|
9
9
|
import { Header } from './header/Header';
|
|
10
|
-
import { View } from 'react-native';
|
|
10
|
+
import { View, StyleSheet } from 'react-native';
|
|
11
11
|
import { useViewContext, ViewContextProvider } from '../useViewContext';
|
|
12
12
|
import { DialogProvider } from './DialogProvider';
|
|
13
13
|
import { useSolidAuth } from '@ldo/solid-react';
|
|
14
14
|
import { SharingModalProvider } from '../sharing/SharingModal';
|
|
15
|
+
import { useTheme } from '@react-navigation/native';
|
|
15
16
|
|
|
16
17
|
export const ValidViewContext = createContext<{
|
|
17
18
|
validViews: ResourceViewConfig[];
|
|
@@ -22,6 +23,7 @@ export const ValidViewContext = createContext<{
|
|
|
22
23
|
|
|
23
24
|
export const Layout: FunctionComponent = () => {
|
|
24
25
|
const { ranInitialAuthCheck } = useSolidAuth();
|
|
26
|
+
const { colors } = useTheme();
|
|
25
27
|
|
|
26
28
|
if (!ranInitialAuthCheck) {
|
|
27
29
|
return <></>;
|
|
@@ -31,9 +33,13 @@ export const Layout: FunctionComponent = () => {
|
|
|
31
33
|
<DialogProvider>
|
|
32
34
|
<ViewContextProvider>
|
|
33
35
|
<SharingModalProvider>
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
<View
|
|
37
|
+
style={[styles.container, { backgroundColor: colors.background }]}
|
|
38
|
+
>
|
|
39
|
+
<Header />
|
|
40
|
+
<View style={styles.contentView}>
|
|
41
|
+
<RenderView />
|
|
42
|
+
</View>
|
|
37
43
|
</View>
|
|
38
44
|
</SharingModalProvider>
|
|
39
45
|
</ViewContextProvider>
|
|
@@ -55,3 +61,13 @@ export const RenderView: FunctionComponent = () => {
|
|
|
55
61
|
const CurView = curViewConfig.view;
|
|
56
62
|
return <CurView />;
|
|
57
63
|
};
|
|
64
|
+
|
|
65
|
+
const styles = StyleSheet.create({
|
|
66
|
+
container: {
|
|
67
|
+
flex: 1,
|
|
68
|
+
},
|
|
69
|
+
contentView: {
|
|
70
|
+
flex: 1,
|
|
71
|
+
zIndex: 0,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import React, { useEffect, useMemo } from 'react';
|
|
2
2
|
import { FunctionComponent, useState } from 'react';
|
|
3
|
-
import { TouchableOpacity, View } from 'react-native';
|
|
3
|
+
import { TouchableOpacity, View, StyleSheet, ScrollView } from 'react-native';
|
|
4
4
|
import { Input } from '../../ui/input';
|
|
5
|
-
import { ChevronRight } from '
|
|
6
|
-
import { ChevronsRight } from '
|
|
7
|
-
import { TextCursorInput } from '
|
|
8
|
-
import { RefreshCw } from '
|
|
9
|
-
import { ArrowRight } from '
|
|
5
|
+
import { ChevronRight } from 'lucide-react-native';
|
|
6
|
+
import { ChevronsRight } from 'lucide-react-native';
|
|
7
|
+
import { TextCursorInput } from 'lucide-react-native';
|
|
8
|
+
import { RefreshCw } from 'lucide-react-native';
|
|
9
|
+
import { ArrowRight } from 'lucide-react-native';
|
|
10
10
|
import { Button } from '../../../components/ui/button';
|
|
11
11
|
import { Text } from '../../ui/text';
|
|
12
12
|
import { useTargetResource } from '../../TargetResourceProvider';
|
|
13
|
+
import { useTheme } from '@react-navigation/native';
|
|
14
|
+
import { Icon } from '../../../components/ui/icon';
|
|
13
15
|
|
|
14
16
|
export const AddressBox: FunctionComponent = () => {
|
|
15
17
|
const [isTextMode, setIsTextMode] = useState(false);
|
|
16
18
|
const { targetUri, refresh, navigateTo, targetResource } =
|
|
17
19
|
useTargetResource();
|
|
20
|
+
const { colors } = useTheme();
|
|
18
21
|
|
|
19
22
|
const [textBoxValue, setTextBoxValue] = useState(targetUri ?? '');
|
|
20
23
|
useEffect(() => {
|
|
@@ -51,9 +54,9 @@ export const AddressBox: FunctionComponent = () => {
|
|
|
51
54
|
}, [targetUri]);
|
|
52
55
|
|
|
53
56
|
return (
|
|
54
|
-
<View
|
|
57
|
+
<View style={styles.container}>
|
|
55
58
|
<Input
|
|
56
|
-
|
|
59
|
+
style={[styles.input, { backgroundColor: colors.border }]}
|
|
57
60
|
onFocus={() => setIsTextMode(true)}
|
|
58
61
|
onBlur={() => setTimeout(() => setIsTextMode(false), 100)}
|
|
59
62
|
onChangeText={setTextBoxValue}
|
|
@@ -66,22 +69,41 @@ export const AddressBox: FunctionComponent = () => {
|
|
|
66
69
|
/>
|
|
67
70
|
<Button
|
|
68
71
|
variant="secondary"
|
|
69
|
-
|
|
72
|
+
style={styles.leftButton}
|
|
70
73
|
onPress={() => setIsTextMode((val) => !val)}
|
|
71
|
-
iconLeft={
|
|
72
|
-
|
|
73
|
-
<ChevronsRight size={20} />
|
|
74
|
-
) : (
|
|
75
|
-
<TextCursorInput size={20} />
|
|
76
|
-
)
|
|
77
|
-
}
|
|
74
|
+
iconLeft={isTextMode ? ChevronsRight : TextCursorInput}
|
|
75
|
+
textStyle={styles.buttonText}
|
|
78
76
|
/>
|
|
77
|
+
<ScrollView
|
|
78
|
+
style={styles.breadcrumbContainer}
|
|
79
|
+
contentContainerStyle={styles.breadcrumbContentContainer}
|
|
80
|
+
pointerEvents="none"
|
|
81
|
+
horizontal
|
|
82
|
+
>
|
|
83
|
+
{!isTextMode &&
|
|
84
|
+
breadcrumbInfo.map((item, index) => (
|
|
85
|
+
<View style={styles.breadcrumbItem} key={item.uri}>
|
|
86
|
+
<TouchableOpacity onPress={() => navigateTo(item.uri)}>
|
|
87
|
+
<View pointerEvents="auto">
|
|
88
|
+
<Text style={styles.breadcrumbText} size="sm">
|
|
89
|
+
{item.name}
|
|
90
|
+
</Text>
|
|
91
|
+
</View>
|
|
92
|
+
</TouchableOpacity>
|
|
93
|
+
{index !== breadcrumbInfo.length - 1 ? (
|
|
94
|
+
<Icon icon={ChevronRight} style={styles.chevron} />
|
|
95
|
+
) : (
|
|
96
|
+
<View style={styles.spacer} />
|
|
97
|
+
)}
|
|
98
|
+
</View>
|
|
99
|
+
))}
|
|
100
|
+
</ScrollView>
|
|
79
101
|
{(() => {
|
|
80
102
|
const shouldRefresh = targetUri === textBoxValue || !isTextMode;
|
|
81
103
|
return (
|
|
82
104
|
<Button
|
|
83
105
|
variant="secondary"
|
|
84
|
-
|
|
106
|
+
style={styles.rightButton}
|
|
85
107
|
onPressIn={() => {
|
|
86
108
|
if (shouldRefresh) {
|
|
87
109
|
refresh();
|
|
@@ -89,39 +111,73 @@ export const AddressBox: FunctionComponent = () => {
|
|
|
89
111
|
navigateTo(textBoxValue);
|
|
90
112
|
}
|
|
91
113
|
}}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
</Text>
|
|
100
|
-
</Button>
|
|
114
|
+
iconLeft={
|
|
115
|
+
shouldRefresh || targetResource?.isLoading()
|
|
116
|
+
? RefreshCw
|
|
117
|
+
: ArrowRight
|
|
118
|
+
}
|
|
119
|
+
textStyle={styles.buttonText}
|
|
120
|
+
/>
|
|
101
121
|
);
|
|
102
122
|
})()}
|
|
103
|
-
<View
|
|
104
|
-
className="absolute top-0 left-0 right-0 bottom-0 flex-row-reverse items-center ml-10 mr-10 overflow-x-auto scrollbar-hide [direction:rtl]"
|
|
105
|
-
pointerEvents="none"
|
|
106
|
-
>
|
|
107
|
-
{!isTextMode &&
|
|
108
|
-
breadcrumbInfo.map((item, index) => (
|
|
109
|
-
<View className="flex-row" key={item.uri}>
|
|
110
|
-
{index !== breadcrumbInfo.length - 1 ? (
|
|
111
|
-
<ChevronRight className="w-4 h-4 mr-0.5 mt-0.5 text-gray-500" />
|
|
112
|
-
) : (
|
|
113
|
-
<View className="w-2" />
|
|
114
|
-
)}
|
|
115
|
-
<TouchableOpacity onPress={() => navigateTo(item.uri)}>
|
|
116
|
-
<View pointerEvents="auto">
|
|
117
|
-
<Text className="mr-0.5 underline" size="sm">
|
|
118
|
-
{item.name}
|
|
119
|
-
</Text>
|
|
120
|
-
</View>
|
|
121
|
-
</TouchableOpacity>
|
|
122
|
-
</View>
|
|
123
|
-
))}
|
|
124
|
-
</View>
|
|
125
123
|
</View>
|
|
126
124
|
);
|
|
127
125
|
};
|
|
126
|
+
|
|
127
|
+
const styles = StyleSheet.create({
|
|
128
|
+
container: {
|
|
129
|
+
flex: 1,
|
|
130
|
+
height: 40,
|
|
131
|
+
},
|
|
132
|
+
input: {
|
|
133
|
+
flex: 1,
|
|
134
|
+
borderWidth: 0,
|
|
135
|
+
paddingHorizontal: 40,
|
|
136
|
+
height: 40,
|
|
137
|
+
fontSize: 14,
|
|
138
|
+
},
|
|
139
|
+
leftButton: {
|
|
140
|
+
position: 'absolute',
|
|
141
|
+
left: 0,
|
|
142
|
+
width: 40,
|
|
143
|
+
height: 40,
|
|
144
|
+
},
|
|
145
|
+
rightButton: {
|
|
146
|
+
position: 'absolute',
|
|
147
|
+
right: 0,
|
|
148
|
+
width: 40,
|
|
149
|
+
height: 40,
|
|
150
|
+
},
|
|
151
|
+
breadcrumbContainer: {
|
|
152
|
+
position: 'absolute',
|
|
153
|
+
top: 0,
|
|
154
|
+
left: 0,
|
|
155
|
+
right: 0,
|
|
156
|
+
bottom: 0,
|
|
157
|
+
marginLeft: 40,
|
|
158
|
+
marginRight: 40,
|
|
159
|
+
},
|
|
160
|
+
breadcrumbContentContainer: {
|
|
161
|
+
flexDirection: 'row',
|
|
162
|
+
alignItems: 'center',
|
|
163
|
+
},
|
|
164
|
+
breadcrumbItem: {
|
|
165
|
+
flexDirection: 'row',
|
|
166
|
+
},
|
|
167
|
+
chevron: {
|
|
168
|
+
width: 16,
|
|
169
|
+
height: 16,
|
|
170
|
+
marginRight: 2,
|
|
171
|
+
color: 'hsl(var(--muted-foreground))',
|
|
172
|
+
},
|
|
173
|
+
spacer: {
|
|
174
|
+
width: 8,
|
|
175
|
+
},
|
|
176
|
+
breadcrumbText: {
|
|
177
|
+
marginRight: 2,
|
|
178
|
+
textDecorationLine: 'underline',
|
|
179
|
+
},
|
|
180
|
+
buttonText: {
|
|
181
|
+
fontSize: 20,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useResource, useSolidAuth, useSubject } from '@ldo/solid-react';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { FunctionComponent } from 'react';
|
|
4
|
-
import { View } from 'react-native';
|
|
4
|
+
import { View, StyleSheet } from 'react-native';
|
|
5
5
|
import { SolidProfileShapeType } from '../../../.ldo/profile.shapeTypes';
|
|
6
6
|
import { Text } from '../../ui/text';
|
|
7
7
|
import { Button } from '../../ui/button';
|
|
@@ -13,9 +13,10 @@ import {
|
|
|
13
13
|
DropdownMenuSeparator,
|
|
14
14
|
DropdownMenuTrigger,
|
|
15
15
|
} from '../../ui/dropdown-menu';
|
|
16
|
-
import { LogOut } from '
|
|
16
|
+
import { LogOut } from 'lucide-react-native';
|
|
17
17
|
import { useTargetResource } from '../../TargetResourceProvider';
|
|
18
18
|
import { ProfileAvatar } from '../../common/ProfileAvatar';
|
|
19
|
+
import { Icon } from '../../ui/icon';
|
|
19
20
|
|
|
20
21
|
export const AvatarMenu: FunctionComponent = () => {
|
|
21
22
|
const { session, logout } = useSolidAuth();
|
|
@@ -29,14 +30,14 @@ export const AvatarMenu: FunctionComponent = () => {
|
|
|
29
30
|
return (
|
|
30
31
|
<DropdownMenu>
|
|
31
32
|
<DropdownMenuTrigger asChild>
|
|
32
|
-
<Button key="setMemu" variant="ghost"
|
|
33
|
+
<Button key="setMemu" variant="ghost" style={styles.button}>
|
|
33
34
|
<ProfileAvatar profile={profile} />
|
|
34
35
|
</Button>
|
|
35
36
|
</DropdownMenuTrigger>
|
|
36
|
-
<DropdownMenuContent
|
|
37
|
-
<View
|
|
38
|
-
<ProfileAvatar profile={profile}
|
|
39
|
-
<View
|
|
37
|
+
<DropdownMenuContent style={styles.dropdownContent}>
|
|
38
|
+
<View style={styles.profileContainer}>
|
|
39
|
+
<ProfileAvatar profile={profile} style={styles.profileAvatar} />
|
|
40
|
+
<View style={styles.profileInfo}>
|
|
40
41
|
<Text>{profile?.fn || ''}</Text>
|
|
41
42
|
<Button
|
|
42
43
|
size="sm"
|
|
@@ -49,11 +50,42 @@ export const AvatarMenu: FunctionComponent = () => {
|
|
|
49
50
|
<ThemeToggleMenu />
|
|
50
51
|
<DropdownMenuSeparator />
|
|
51
52
|
<DropdownMenuItem onPress={logout}>
|
|
52
|
-
<
|
|
53
|
-
<LogOut />
|
|
54
|
-
|
|
53
|
+
<View style={styles.logoutText}>
|
|
54
|
+
<Icon icon={LogOut} />
|
|
55
|
+
<Text>Log Out</Text>
|
|
56
|
+
</View>
|
|
55
57
|
</DropdownMenuItem>
|
|
56
58
|
</DropdownMenuContent>
|
|
57
59
|
</DropdownMenu>
|
|
58
60
|
);
|
|
59
61
|
};
|
|
62
|
+
|
|
63
|
+
const styles = StyleSheet.create({
|
|
64
|
+
button: {
|
|
65
|
+
width: 40,
|
|
66
|
+
},
|
|
67
|
+
dropdownContent: {
|
|
68
|
+
width: 256,
|
|
69
|
+
marginRight: 8,
|
|
70
|
+
marginTop: 8,
|
|
71
|
+
},
|
|
72
|
+
profileContainer: {
|
|
73
|
+
padding: 8,
|
|
74
|
+
flexDirection: 'row',
|
|
75
|
+
alignItems: 'center',
|
|
76
|
+
},
|
|
77
|
+
profileAvatar: {
|
|
78
|
+
width: 80,
|
|
79
|
+
height: 80,
|
|
80
|
+
borderRadius: 40,
|
|
81
|
+
},
|
|
82
|
+
profileInfo: {
|
|
83
|
+
marginLeft: 8,
|
|
84
|
+
gap: 8,
|
|
85
|
+
},
|
|
86
|
+
logoutText: {
|
|
87
|
+
flexDirection: 'row',
|
|
88
|
+
gap: 4,
|
|
89
|
+
alignItems: 'center',
|
|
90
|
+
},
|
|
91
|
+
});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useSolidAuth } from '@ldo/solid-react';
|
|
3
3
|
import { FunctionComponent } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { StyleSheet } from 'react-native';
|
|
5
5
|
import { AddressBox } from './AddressBox';
|
|
6
6
|
import { AvatarMenu } from './AvatarMenu';
|
|
7
7
|
import { SignInMenu } from './SignInMenu';
|
|
8
8
|
import { ViewMenu } from './ViewMenu';
|
|
9
9
|
import { Card } from '../../ui/card';
|
|
10
10
|
import { Button } from '../../ui/button';
|
|
11
|
-
import { UserPlus } from '
|
|
11
|
+
import { UserPlus } from 'lucide-react-native';
|
|
12
12
|
import { useSharingModal } from '../../sharing/SharingModal';
|
|
13
13
|
|
|
14
14
|
export const Header: FunctionComponent = () => {
|
|
@@ -16,28 +16,35 @@ export const Header: FunctionComponent = () => {
|
|
|
16
16
|
const { openSharingModal } = useSharingModal();
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
|
-
<Card
|
|
20
|
-
className={
|
|
21
|
-
'h-12 flex-row justify-between items-center rounded-none border-0 sm:p-2 p-1 z-[1]'
|
|
22
|
-
}
|
|
23
|
-
>
|
|
19
|
+
<Card style={styles.card}>
|
|
24
20
|
<AddressBox />
|
|
25
|
-
<View className="mr-1" />
|
|
26
21
|
{session.isLoggedIn && (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/>
|
|
35
|
-
<View className="mr-1" />
|
|
36
|
-
</>
|
|
22
|
+
<Button
|
|
23
|
+
key="setMemu"
|
|
24
|
+
variant="ghost"
|
|
25
|
+
style={styles.shareButton}
|
|
26
|
+
onPress={openSharingModal}
|
|
27
|
+
iconLeft={UserPlus}
|
|
28
|
+
/>
|
|
37
29
|
)}
|
|
38
30
|
<ViewMenu />
|
|
39
|
-
<View className="mr-1" />
|
|
40
31
|
{session.isLoggedIn ? <AvatarMenu /> : <SignInMenu />}
|
|
41
32
|
</Card>
|
|
42
33
|
);
|
|
43
34
|
};
|
|
35
|
+
|
|
36
|
+
const styles = StyleSheet.create({
|
|
37
|
+
card: {
|
|
38
|
+
height: 48, // h-12 = 3rem = 48px
|
|
39
|
+
flexDirection: 'row',
|
|
40
|
+
justifyContent: 'space-between',
|
|
41
|
+
alignItems: 'center',
|
|
42
|
+
borderRadius: 0, // rounded-none
|
|
43
|
+
borderWidth: 0, // border-0
|
|
44
|
+
padding: 8,
|
|
45
|
+
zIndex: 1, // z-[1]
|
|
46
|
+
},
|
|
47
|
+
shareButton: {
|
|
48
|
+
width: 40, // w-10 = 2.5rem = 40px
|
|
49
|
+
},
|
|
50
|
+
});
|