linked-data-browser 0.0.3 → 0.0.5

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.
Files changed (46) hide show
  1. package/.eslintrc.js +19 -0
  2. package/.ldo/profile.context.ts +14 -0
  3. package/.ldo/profile.typings.ts +6 -4
  4. package/app/index.tsx +2 -1
  5. package/components/ResourceView.tsx +7 -2
  6. package/components/common/LoadingBar.tsx +27 -0
  7. package/components/common/ProfileAvatar.tsx +28 -0
  8. package/components/nav/DialogProvider.tsx +2 -6
  9. package/components/nav/Layout.tsx +13 -81
  10. package/components/nav/header/AddressBox.tsx +8 -7
  11. package/components/nav/header/AvatarMenu.tsx +9 -36
  12. package/components/nav/header/Header.tsx +17 -2
  13. package/components/nav/header/SignInMenu.tsx +11 -14
  14. package/components/nav/header/ViewMenu.tsx +4 -4
  15. package/components/sharing/AccessDropdown.tsx +95 -0
  16. package/components/sharing/CopyLink.tsx +21 -0
  17. package/components/sharing/PermissionRow.tsx +38 -0
  18. package/components/sharing/SharingModal.tsx +149 -0
  19. package/components/sharing/WacRuleForm.tsx +44 -0
  20. package/components/sharing/agentPermissions/AgentInformation.tsx +37 -0
  21. package/components/sharing/agentPermissions/AgentInput.tsx +126 -0
  22. package/components/sharing/agentPermissions/AgentPermissionRow.tsx +36 -0
  23. package/components/sharing/agentPermissions/AgentPermissions.tsx +56 -0
  24. package/components/sharing/agentPermissions/useContactFilter.ts +35 -0
  25. package/components/ui/button.tsx +52 -5
  26. package/components/ui/dialog.tsx +1 -1
  27. package/components/ui/input-dropdown.tsx +105 -0
  28. package/components/ui/input.tsx +34 -2
  29. package/components/ui/text.tsx +47 -0
  30. package/components/useViewContext.tsx +141 -0
  31. package/components/{nav/utilityResourceViews → utilityResourceViews}/ErrorMessageResourceView.tsx +2 -2
  32. package/lib/icons/Fingerprint.tsx +4 -0
  33. package/lib/icons/Link.tsx +4 -0
  34. package/lib/icons/Loader.tsx +4 -0
  35. package/lib/icons/Plus.tsx +4 -0
  36. package/lib/icons/Save.tsx +4 -0
  37. package/lib/icons/UserPlus.tsx +4 -0
  38. package/lib/icons/Users.tsx +4 -0
  39. package/package.json +14 -8
  40. package/resourceViews/Container/ContainerView.tsx +5 -6
  41. package/resourceViews/Profile/ProfileConfig.tsx +20 -0
  42. package/resourceViews/Profile/ProfileKnows.tsx +65 -0
  43. package/resourceViews/Profile/ProfileView.tsx +59 -0
  44. package/resourceViews/RawCode/RawCodeView.tsx +29 -8
  45. package/test-server/server-config.json +1 -1
  46. package/components/nav/useValidView.tsx +0 -51
package/.eslintrc.js CHANGED
@@ -9,5 +9,24 @@ module.exports = {
9
9
  'prettier/prettier': ['error'],
10
10
  'react/no-unstable-nested-components': 0,
11
11
  '@typescript-eslint/no-unused-vars': 1,
12
+ 'no-restricted-imports': [
13
+ 'error',
14
+ {
15
+ patterns: [
16
+ {
17
+ group: [
18
+ 'components/*',
19
+ '~/components/*',
20
+ 'lib/*',
21
+ '~/lib/*',
22
+ 'resourceViews/*',
23
+ '~/resourceViews/*',
24
+ ],
25
+ message:
26
+ 'Absolute imports are not allowed. Please use relative imports instead.',
27
+ },
28
+ ],
29
+ },
30
+ ],
12
31
  },
13
32
  };
@@ -8,12 +8,14 @@ import { LdoJsonldContext } from "@ldo/ldo";
8
8
  export const profileContext: LdoJsonldContext = {
9
9
  type: {
10
10
  "@id": "@type",
11
+ "@isCollection": true,
11
12
  },
12
13
  Person: {
13
14
  "@id": "http://schema.org/Person",
14
15
  "@context": {
15
16
  type: {
16
17
  "@id": "@type",
18
+ "@isCollection": true,
17
19
  },
18
20
  fn: {
19
21
  "@id": "http://www.w3.org/2006/vcard/ns#fn",
@@ -107,6 +109,7 @@ export const profileContext: LdoJsonldContext = {
107
109
  "@context": {
108
110
  type: {
109
111
  "@id": "@type",
112
+ "@isCollection": true,
110
113
  },
111
114
  fn: {
112
115
  "@id": "http://www.w3.org/2006/vcard/ns#fn",
@@ -238,6 +241,7 @@ export const profileContext: LdoJsonldContext = {
238
241
  "@context": {
239
242
  type: {
240
243
  "@id": "@type",
244
+ "@isCollection": true,
241
245
  },
242
246
  value: {
243
247
  "@id": "http://www.w3.org/2006/vcard/ns#value",
@@ -250,6 +254,7 @@ export const profileContext: LdoJsonldContext = {
250
254
  "@context": {
251
255
  type: {
252
256
  "@id": "@type",
257
+ "@isCollection": true,
253
258
  },
254
259
  value: {
255
260
  "@id": "http://www.w3.org/2006/vcard/ns#value",
@@ -262,6 +267,7 @@ export const profileContext: LdoJsonldContext = {
262
267
  "@context": {
263
268
  type: {
264
269
  "@id": "@type",
270
+ "@isCollection": true,
265
271
  },
266
272
  value: {
267
273
  "@id": "http://www.w3.org/2006/vcard/ns#value",
@@ -274,6 +280,7 @@ export const profileContext: LdoJsonldContext = {
274
280
  "@context": {
275
281
  type: {
276
282
  "@id": "@type",
283
+ "@isCollection": true,
277
284
  },
278
285
  value: {
279
286
  "@id": "http://www.w3.org/2006/vcard/ns#value",
@@ -286,6 +293,7 @@ export const profileContext: LdoJsonldContext = {
286
293
  "@context": {
287
294
  type: {
288
295
  "@id": "@type",
296
+ "@isCollection": true,
289
297
  },
290
298
  value: {
291
299
  "@id": "http://www.w3.org/2006/vcard/ns#value",
@@ -298,6 +306,7 @@ export const profileContext: LdoJsonldContext = {
298
306
  "@context": {
299
307
  type: {
300
308
  "@id": "@type",
309
+ "@isCollection": true,
301
310
  },
302
311
  value: {
303
312
  "@id": "http://www.w3.org/2006/vcard/ns#value",
@@ -310,6 +319,7 @@ export const profileContext: LdoJsonldContext = {
310
319
  "@context": {
311
320
  type: {
312
321
  "@id": "@type",
322
+ "@isCollection": true,
313
323
  },
314
324
  value: {
315
325
  "@id": "http://www.w3.org/2006/vcard/ns#value",
@@ -322,6 +332,7 @@ export const profileContext: LdoJsonldContext = {
322
332
  "@context": {
323
333
  type: {
324
334
  "@id": "@type",
335
+ "@isCollection": true,
325
336
  },
326
337
  value: {
327
338
  "@id": "http://www.w3.org/2006/vcard/ns#value",
@@ -334,6 +345,7 @@ export const profileContext: LdoJsonldContext = {
334
345
  "@context": {
335
346
  type: {
336
347
  "@id": "@type",
348
+ "@isCollection": true,
337
349
  },
338
350
  value: {
339
351
  "@id": "http://www.w3.org/2006/vcard/ns#value",
@@ -346,6 +358,7 @@ export const profileContext: LdoJsonldContext = {
346
358
  "@context": {
347
359
  type: {
348
360
  "@id": "@type",
361
+ "@isCollection": true,
349
362
  },
350
363
  value: {
351
364
  "@id": "http://www.w3.org/2006/vcard/ns#value",
@@ -358,6 +371,7 @@ export const profileContext: LdoJsonldContext = {
358
371
  "@context": {
359
372
  type: {
360
373
  "@id": "@type",
374
+ "@isCollection": true,
361
375
  },
362
376
  value: {
363
377
  "@id": "http://www.w3.org/2006/vcard/ns#value",
@@ -154,7 +154,7 @@ export interface EmailShape {
154
154
  /**
155
155
  * The type of email.
156
156
  */
157
- type?:
157
+ type?: LdSet<
158
158
  | {
159
159
  "@id": "Dom";
160
160
  }
@@ -187,7 +187,8 @@ export interface EmailShape {
187
187
  }
188
188
  | {
189
189
  "@id": "X400";
190
- };
190
+ }
191
+ >;
191
192
  /**
192
193
  * The value of an email as a mailto link (Example <mailto:jane@example.com>)
193
194
  */
@@ -205,7 +206,7 @@ export interface PhoneNumberShape {
205
206
  /**
206
207
  * They type of Phone Number
207
208
  */
208
- type?:
209
+ type?: LdSet<
209
210
  | {
210
211
  "@id": "Dom";
211
212
  }
@@ -238,7 +239,8 @@ export interface PhoneNumberShape {
238
239
  }
239
240
  | {
240
241
  "@id": "X400";
241
- };
242
+ }
243
+ >;
242
244
  /**
243
245
  * The value of a phone number as a tel link (Example <tel:555-555-5555>)
244
246
  */
package/app/index.tsx CHANGED
@@ -5,6 +5,7 @@ import { RawCodeConfig } from '../resourceViews/RawCode/RawCodeConfig';
5
5
  import { ContainerConfig } from '../resourceViews/Container/ContainerConfig';
6
6
  import { SafeAreaProvider } from 'react-native-safe-area-context';
7
7
  import { StatusBar } from 'react-native';
8
+ import { ProfileConfig } from '../resourceViews/Profile/ProfileConfig';
8
9
 
9
10
  export function Screen() {
10
11
  const mode = process.env.EXPO_PUBLIC_IS_SERVER_HOSTED
@@ -15,7 +16,7 @@ export function Screen() {
15
16
  <SafeAreaProvider>
16
17
  <StatusBar />
17
18
  <DataBrowser
18
- views={[ContainerConfig, RawCodeConfig]}
19
+ views={[ProfileConfig, ContainerConfig, RawCodeConfig]}
19
20
  mode={mode}
20
21
  renderHomepage={() => <Text>Hopepage</Text>}
21
22
  renderLogo={() => <Text>Logo</Text>}
@@ -1,7 +1,11 @@
1
- import { SolidContainer, SolidLeaf } from '@ldo/connected-solid';
1
+ import {
2
+ SolidConnectedPlugin,
3
+ SolidContainer,
4
+ SolidLeaf,
5
+ } from '@ldo/connected-solid';
6
+ import { ConnectedLdoDataset } from '@ldo/connected';
2
7
  import { LucideIcon } from 'lucide-react-native';
3
8
  import { ElementType } from 'react';
4
-
5
9
  export interface ResourceViewConfig {
6
10
  name: string;
7
11
  displayName: string;
@@ -10,5 +14,6 @@ export interface ResourceViewConfig {
10
14
  canDisplay: (
11
15
  targetUri: string,
12
16
  targetResource: SolidLeaf | SolidContainer,
17
+ dataset: ConnectedLdoDataset<SolidConnectedPlugin[]>,
13
18
  ) => boolean;
14
19
  }
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import { useTheme } from '@react-navigation/native';
3
+ import { FunctionComponent } from 'react';
4
+ import { Bar } from 'react-native-progress';
5
+
6
+ interface LoadingBarProps {
7
+ isLoading: boolean;
8
+ }
9
+
10
+ export const LoadingBar: FunctionComponent<LoadingBarProps> = ({
11
+ isLoading,
12
+ }) => {
13
+ const { colors } = useTheme();
14
+
15
+ if (!isLoading) return <></>;
16
+
17
+ return (
18
+ <Bar
19
+ color={colors.primary}
20
+ indeterminate
21
+ borderWidth={0}
22
+ borderRadius={0}
23
+ width={null}
24
+ className="absolute top-0 left-0 right-0"
25
+ />
26
+ );
27
+ };
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { SolidProfileShape } from '.ldo/profile.typings';
3
+ import { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar';
4
+ import { Text } from '../ui/text';
5
+ import { User } from '../../lib/icons/User';
6
+ import { FunctionComponent } from 'react';
7
+
8
+ interface ProfileAvatarProps {
9
+ profile?: SolidProfileShape;
10
+ className?: string;
11
+ }
12
+
13
+ export const ProfileAvatar: FunctionComponent<ProfileAvatarProps> = ({
14
+ profile,
15
+ className,
16
+ }) => (
17
+ <Avatar
18
+ alt={profile?.fn ? `${profile.fn}'s Avatar` : ''}
19
+ className={className}
20
+ >
21
+ <AvatarImage source={{ uri: profile?.hasPhoto?.['@id'] }} />
22
+ <AvatarFallback>
23
+ <Text>
24
+ <User />
25
+ </Text>
26
+ </AvatarFallback>
27
+ </Avatar>
28
+ );
@@ -126,13 +126,9 @@ export const DialogProvider: React.FC<{ children: React.ReactNode }> = ({
126
126
 
127
127
  <DialogFooter>
128
128
  <DialogClose asChild>
129
- <Button variant="ghost" onPress={handleCancel}>
130
- <Text>Cancel</Text>
131
- </Button>
129
+ <Button variant="ghost" onPress={handleCancel} text="Cancel" />
132
130
  </DialogClose>
133
- <Button onPress={handleConfirm}>
134
- <Text>Ok</Text>
135
- </Button>
131
+ <Button onPress={handleConfirm} text="Ok" />
136
132
  </DialogFooter>
137
133
  </DialogContent>
138
134
  </Dialog>
@@ -4,19 +4,14 @@ import React, {
4
4
  FunctionComponent,
5
5
  SetStateAction,
6
6
  } from 'react';
7
- import { useTargetResource } from '../TargetResourceProvider';
8
7
  import { ResourceViewConfig } from '../ResourceView';
9
- import { ErrorMessageResourceView } from './utilityResourceViews/ErrorMessageResourceView';
10
- import { TextCursorInput } from '../../lib/icons/TextCursorInput';
11
- import { CircleSlash } from '../../lib/icons/CircleSlash';
12
- import { OctagonX } from '../../lib/icons/OctagonX';
13
- import { ShieldX } from '../../lib/icons/ShieldX';
14
- import { CircleX } from '../../lib/icons/CircleX';
8
+
15
9
  import { Header } from './header/Header';
16
10
  import { View } from 'react-native';
17
- import { useValidView, ValidViewProvider } from './useValidView';
11
+ import { useViewContext, ViewContextProvider } from '../useViewContext';
18
12
  import { DialogProvider } from './DialogProvider';
19
13
  import { useSolidAuth } from '@ldo/solid-react';
14
+ import { SharingModalProvider } from '../sharing/SharingModal';
20
15
 
21
16
  export const ValidViewContext = createContext<{
22
17
  validViews: ResourceViewConfig[];
@@ -34,12 +29,14 @@ export const Layout: FunctionComponent = () => {
34
29
 
35
30
  return (
36
31
  <DialogProvider>
37
- <ValidViewProvider>
38
- <Header />
39
- <View className="flex-1 z-0">
40
- <RenderView />
41
- </View>
42
- </ValidViewProvider>
32
+ <ViewContextProvider>
33
+ <SharingModalProvider>
34
+ <Header />
35
+ <View className="flex-1 z-0">
36
+ <RenderView />
37
+ </View>
38
+ </SharingModalProvider>
39
+ </ViewContextProvider>
43
40
  </DialogProvider>
44
41
  );
45
42
  };
@@ -51,75 +48,10 @@ export const Layout: FunctionComponent = () => {
51
48
  */
52
49
 
53
50
  export const RenderView: FunctionComponent = () => {
54
- const { targetUri, targetResource } = useTargetResource();
51
+ const { curViewConfig, targetResource } = useViewContext();
55
52
 
56
- const { curViewConfig } = useValidView();
53
+ if (targetResource?.isDoingInitialFetch()) return <></>;
57
54
 
58
- // Handle Edge cases
59
- if (!targetResource || !targetUri) {
60
- return (
61
- <ErrorMessageResourceView
62
- icon={TextCursorInput}
63
- message="Enter a URI in the address bar to view a resource."
64
- />
65
- );
66
- } else if (targetResource.type === 'InvalidIdentifierResouce') {
67
- return (
68
- <ErrorMessageResourceView
69
- icon={CircleSlash}
70
- message={`${targetResource.uri} is an invalid URI.`}
71
- />
72
- );
73
- } else if (targetResource?.isDoingInitialFetch()) {
74
- return <></>;
75
- } else if (targetResource?.isAbsent()) {
76
- return (
77
- <ErrorMessageResourceView
78
- icon={CircleSlash}
79
- message={`${targetResource.uri} either doesn't exist or you don't have read access to it.`}
80
- />
81
- );
82
- } else if (targetResource?.status.isError) {
83
- switch (targetResource.status.type) {
84
- case 'noncompliantPodError':
85
- return (
86
- <ErrorMessageResourceView
87
- icon={OctagonX}
88
- message={`${targetResource.uri} returned a response that is not compliant with the Linked Web Storage specification: ${targetResource.status.message}`}
89
- />
90
- );
91
- case 'serverError':
92
- return (
93
- <ErrorMessageResourceView
94
- icon={OctagonX}
95
- message={`${targetResource.uri} encountered an internal server error: ${targetResource.status.message}`}
96
- />
97
- );
98
- case 'unauthenticatedError':
99
- return (
100
- <ErrorMessageResourceView
101
- icon={ShieldX}
102
- message={`${targetResource.uri} requires you to log in to view.`}
103
- />
104
- );
105
- case 'unauthorizedError':
106
- return (
107
- <ErrorMessageResourceView
108
- icon={ShieldX}
109
- message={`You don't have access to ${targetResource.uri}.`}
110
- />
111
- );
112
- case 'unexpectedHttpError':
113
- case 'unexpectedResourceError':
114
- default:
115
- return (
116
- <ErrorMessageResourceView
117
- icon={CircleX}
118
- message={`An unexpected error occurred: ${targetResource.status.message}.`}
119
- />
120
- );
121
- }
122
- }
123
55
  const CurView = curViewConfig.view;
124
56
  return <CurView />;
125
57
  };
@@ -68,15 +68,14 @@ export const AddressBox: FunctionComponent = () => {
68
68
  variant="secondary"
69
69
  className="absolute left-0 w-10 h-10"
70
70
  onPress={() => setIsTextMode((val) => !val)}
71
- >
72
- <Text>
73
- {isTextMode ? (
71
+ iconLeft={
72
+ isTextMode ? (
74
73
  <ChevronsRight size={20} />
75
74
  ) : (
76
75
  <TextCursorInput size={20} />
77
- )}
78
- </Text>
79
- </Button>
76
+ )
77
+ }
78
+ />
80
79
  {(() => {
81
80
  const shouldRefresh = targetUri === textBoxValue || !isTextMode;
82
81
  return (
@@ -115,7 +114,9 @@ export const AddressBox: FunctionComponent = () => {
115
114
  )}
116
115
  <TouchableOpacity onPress={() => navigateTo(item.uri)}>
117
116
  <View pointerEvents="auto">
118
- <Text className="mr-0.5 underline text-sm">{item.name}</Text>
117
+ <Text className="mr-0.5 underline" size="sm">
118
+ {item.name}
119
+ </Text>
119
120
  </View>
120
121
  </TouchableOpacity>
121
122
  </View>
@@ -1,14 +1,8 @@
1
- import {
2
- useLdo,
3
- useResource,
4
- useSolidAuth,
5
- useSubject,
6
- } from '@ldo/solid-react';
1
+ import { useResource, useSolidAuth, useSubject } from '@ldo/solid-react';
7
2
  import React from 'react';
8
3
  import { FunctionComponent } from 'react';
9
4
  import { View } from 'react-native';
10
5
  import { SolidProfileShapeShapeType } from '../../../.ldo/profile.shapeTypes';
11
- import { Avatar, AvatarFallback, AvatarImage } from '../../ui/avatar';
12
6
  import { Text } from '../../ui/text';
13
7
  import { Button } from '../../ui/button';
14
8
  import { ThemeToggleMenu } from './ThemeToggleMenu';
@@ -19,12 +13,11 @@ import {
19
13
  DropdownMenuSeparator,
20
14
  DropdownMenuTrigger,
21
15
  } from '../../ui/dropdown-menu';
22
- import { User } from '../../../lib/icons/User';
23
16
  import { LogOut } from '../../../lib/icons/LogOut';
24
17
  import { useTargetResource } from '../../TargetResourceProvider';
18
+ import { ProfileAvatar } from '../../common/ProfileAvatar';
25
19
 
26
20
  export const AvatarMenu: FunctionComponent = () => {
27
- const { dataset } = useLdo();
28
21
  const { session, logout } = useSolidAuth();
29
22
  // TODO: Use WebId Resource to render a skeleton loader
30
23
  const webIdResource = useResource(session.webId);
@@ -33,43 +26,23 @@ export const AvatarMenu: FunctionComponent = () => {
33
26
 
34
27
  if (!session.webId) return <></>;
35
28
 
36
- console.log(profile?.['@id']);
37
- console.log(profile?.hasPhoto?.['@id']);
38
- console.log(webIdResource?.isLoading());
39
- console.log(dataset.toString());
40
-
41
29
  return (
42
30
  <DropdownMenu>
43
31
  <DropdownMenuTrigger asChild>
44
32
  <Button key="setMemu" variant="ghost" className="w-10">
45
- <Avatar alt={profile?.fn ? `${profile.fn}'s Avatar` : ''}>
46
- <AvatarImage source={{ uri: profile?.hasPhoto?.['@id'] }} />
47
- <AvatarFallback>
48
- <Text>
49
- <User />
50
- </Text>
51
- </AvatarFallback>
52
- </Avatar>
33
+ <ProfileAvatar profile={profile} />
53
34
  </Button>
54
35
  </DropdownMenuTrigger>
55
36
  <DropdownMenuContent className="w-64 native:w-72 mr-2 mt-2">
56
37
  <View className="p-2 flex-row items-center">
57
- <Avatar
58
- alt={profile?.fn ? `${profile.fn}'s Avatar` : ''}
59
- className="w-20 h-20"
60
- >
61
- <AvatarImage source={{ uri: profile?.hasPhoto?.['@id'] }} />
62
- <AvatarFallback>
63
- <Text>
64
- <User />
65
- </Text>
66
- </AvatarFallback>
67
- </Avatar>
38
+ <ProfileAvatar profile={profile} className="w-20 h-20" />
68
39
  <View className="ml-2">
69
40
  <Text>{profile?.fn || ''}</Text>
70
- <Button size="sm" onPress={() => navigateTo(session.webId ?? '')}>
71
- <Text>Edit your profile</Text>
72
- </Button>
41
+ <Button
42
+ size="sm"
43
+ onPress={() => navigateTo(session.webId ?? '')}
44
+ text="Edit your profile"
45
+ />
73
46
  </View>
74
47
  </View>
75
48
  <DropdownMenuSeparator />
@@ -2,15 +2,18 @@ import React from 'react';
2
2
  import { useSolidAuth } from '@ldo/solid-react';
3
3
  import { FunctionComponent } from 'react';
4
4
  import { View } from 'react-native';
5
-
6
5
  import { AddressBox } from './AddressBox';
7
6
  import { AvatarMenu } from './AvatarMenu';
8
7
  import { SignInMenu } from './SignInMenu';
9
8
  import { ViewMenu } from './ViewMenu';
10
- import { Card } from '../../../components/ui/card';
9
+ import { Card } from '../../ui/card';
10
+ import { Button } from '../../ui/button';
11
+ import { UserPlus } from '../../../lib/icons/UserPlus';
12
+ import { useSharingModal } from '../../sharing/SharingModal';
11
13
 
12
14
  export const Header: FunctionComponent = () => {
13
15
  const { session } = useSolidAuth();
16
+ const { openSharingModal } = useSharingModal();
14
17
 
15
18
  return (
16
19
  <Card
@@ -20,6 +23,18 @@ export const Header: FunctionComponent = () => {
20
23
  >
21
24
  <AddressBox />
22
25
  <View className="mr-1" />
26
+ {session.isLoggedIn && (
27
+ <>
28
+ <Button
29
+ key="setMemu"
30
+ variant="ghost"
31
+ className="w-10"
32
+ onPress={openSharingModal}
33
+ iconLeft={<UserPlus />}
34
+ />
35
+ <View className="mr-1" />
36
+ </>
37
+ )}
23
38
  <ViewMenu />
24
39
  <View className="mr-1" />
25
40
  {session.isLoggedIn ? <AvatarMenu /> : <SignInMenu />}
@@ -53,24 +53,23 @@ export const SignInMenu: FunctionComponent = () => {
53
53
  className="hidden sm:block"
54
54
  onPress={() => signUp(DEFAULT_ISSUER)}
55
55
  variant="ghost"
56
- >
57
- <Text>Sign Up</Text>
58
- </Button>
56
+ text="Sign Up"
57
+ />
59
58
  <Button
60
59
  key="logIn"
61
60
  className="hidden sm:block"
62
61
  onPress={() => login(DEFAULT_ISSUER)}
63
62
  variant="default"
64
- >
65
- <Text>Log In</Text>
66
- </Button>
63
+ text="Log In"
64
+ />
67
65
  <DropdownMenu>
68
66
  <DropdownMenuTrigger asChild>
69
- <Button key="setMemu" variant="ghost" className="w-10">
70
- <Text>
71
- <EllipsisVertical size={20} />
72
- </Text>
73
- </Button>
67
+ <Button
68
+ key="setMemu"
69
+ variant="ghost"
70
+ className="w-10"
71
+ iconLeft={<EllipsisVertical size={20} />}
72
+ />
74
73
  </DropdownMenuTrigger>
75
74
  <DropdownMenuContent className="w-64 native:w-72">
76
75
  <DropdownMenuGroup>
@@ -106,9 +105,7 @@ export const SignInMenu: FunctionComponent = () => {
106
105
  </DialogHeader>
107
106
  <DialogFooter>
108
107
  <DialogClose asChild>
109
- <Button onPress={onIdpSubmit}>
110
- <Text>OK</Text>
111
- </Button>
108
+ <Button onPress={onIdpSubmit} text="OK" />
112
109
  </DialogClose>
113
110
  </DialogFooter>
114
111
  </DialogContent>
@@ -13,7 +13,7 @@ import { View } from 'react-native';
13
13
  import type { ViewRef } from '@rn-primitives/types';
14
14
  import { cn } from '../../../lib/utils';
15
15
  import { ViewIcon } from '../../../lib/icons/ViewIcon';
16
- import { useValidView } from '../useValidView';
16
+ import { useViewContext } from '../../useViewContext';
17
17
  import { ResourceViewConfig } from '../../../components/ResourceView';
18
18
 
19
19
  export const ViewMenu: FunctionComponent = () => {
@@ -24,7 +24,7 @@ export const ViewMenu: FunctionComponent = () => {
24
24
  left: 12,
25
25
  right: 12,
26
26
  };
27
- const { validViews } = useValidView();
27
+ const { validViews } = useViewContext();
28
28
 
29
29
  const [isOpen, setIsOpen] = React.useState<string>();
30
30
 
@@ -63,7 +63,7 @@ const ListItem = React.forwardRef<
63
63
  }
64
64
  >(({ className, viewConfig, ...props }, ref) => {
65
65
  // TODO: add navigationn to `href` on `NavigationMenuLink` onPress
66
- const { curViewConfig, setCurViewConfig } = useValidView();
66
+ const { curViewConfig, setCurViewConfig } = useViewContext();
67
67
  const Icon = viewConfig.displayIcon;
68
68
  return (
69
69
  <View role="listitem">
@@ -78,7 +78,7 @@ const ListItem = React.forwardRef<
78
78
  {...props}
79
79
  >
80
80
  <Icon size={20} />
81
- <Text className="text-sm native:text-base font-medium text-foreground leading-none ml-2">
81
+ <Text className="ml-2" size="sm">
82
82
  {viewConfig.displayName}
83
83
  </Text>
84
84
  </NavigationMenuLink>