linked-data-browser 0.0.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/.eslintrc.js +13 -0
- package/.ldo/profile.context.ts +459 -0
- package/.ldo/profile.schema.ts +751 -0
- package/.ldo/profile.shapeTypes.ts +71 -0
- package/.ldo/profile.typings.ts +295 -0
- package/.prettierignore +6 -0
- package/.prettierrc +10 -0
- package/.shapes/profile.shex +121 -0
- package/README.md +3 -0
- package/app/index.tsx +25 -0
- package/app.json +37 -0
- package/assets/images/adaptive-icon.png +0 -0
- package/assets/images/favicon.png +0 -0
- package/assets/images/icon.png +0 -0
- package/assets/images/splash.png +0 -0
- package/babel.config.js +6 -0
- package/components/DataBrowser.tsx +57 -0
- package/components/ResourceView.tsx +14 -0
- package/components/TargetResourceProvider.tsx +128 -0
- package/components/ThemeProvider.tsx +123 -0
- package/components/nav/DialogProvider.tsx +140 -0
- package/components/nav/Layout.tsx +118 -0
- package/components/nav/header/AddressBox.tsx +126 -0
- package/components/nav/header/AvatarMenu.tsx +62 -0
- package/components/nav/header/Header.tsx +28 -0
- package/components/nav/header/SignInMenu.tsx +126 -0
- package/components/nav/header/ThemeToggleMenu.tsx +34 -0
- package/components/nav/header/ViewMenu.tsx +88 -0
- package/components/nav/useValidView.tsx +51 -0
- package/components/nav/utilityResourceViews/ErrorMessageResourceView.tsx +26 -0
- package/components/ui/avatar.tsx +53 -0
- package/components/ui/button.tsx +88 -0
- package/components/ui/card.tsx +101 -0
- package/components/ui/dialog.tsx +159 -0
- package/components/ui/dropdown-menu.tsx +275 -0
- package/components/ui/input.tsx +25 -0
- package/components/ui/label.tsx +34 -0
- package/components/ui/navigation-menu.tsx +200 -0
- package/components/ui/popover.tsx +45 -0
- package/components/ui/progress.tsx +79 -0
- package/components/ui/radio-group.tsx +59 -0
- package/components/ui/separator.tsx +27 -0
- package/components/ui/switch.tsx +105 -0
- package/components/ui/text.tsx +30 -0
- package/components/ui/tooltip.tsx +46 -0
- package/components.json +7 -0
- package/global.css +61 -0
- package/index.js +12 -0
- package/lib/android-navigation-bar.ts +11 -0
- package/lib/constants.ts +18 -0
- package/lib/icons/ArrowRight.tsx +4 -0
- package/lib/icons/Check.tsx +4 -0
- package/lib/icons/ChevronDown.tsx +4 -0
- package/lib/icons/ChevronRight.tsx +4 -0
- package/lib/icons/ChevronUp.tsx +4 -0
- package/lib/icons/ChevronsRight.tsx +4 -0
- package/lib/icons/CircleSlash.tsx +4 -0
- package/lib/icons/CircleX.tsx +4 -0
- package/lib/icons/Code.tsx +4 -0
- package/lib/icons/EllipsisVertical.tsx +4 -0
- package/lib/icons/EyeOff.tsx +4 -0
- package/lib/icons/File.tsx +4 -0
- package/lib/icons/Folder.tsx +4 -0
- package/lib/icons/Folders.tsx +4 -0
- package/lib/icons/Info.tsx +4 -0
- package/lib/icons/MonitorSmartphone.tsx +4 -0
- package/lib/icons/MoonStar.tsx +4 -0
- package/lib/icons/OctagonX.tsx +4 -0
- package/lib/icons/RefreshCw.tsx +4 -0
- package/lib/icons/ShieldX.tsx +4 -0
- package/lib/icons/Sun.tsx +4 -0
- package/lib/icons/TextCursorInput.tsx +4 -0
- package/lib/icons/Trash.tsx +4 -0
- package/lib/icons/ViewIcon.tsx +4 -0
- package/lib/icons/X.tsx +4 -0
- package/lib/icons/iconWithClassName.ts +14 -0
- package/lib/utils.ts +6 -0
- package/metro.config.js +6 -0
- package/nativewind-env.d.ts +1 -0
- package/package.json +89 -0
- package/resourceViews/Container/ContainerConfig.tsx +13 -0
- package/resourceViews/Container/ContainerView.tsx +148 -0
- package/resourceViews/RawCode/RawCodeConfig.tsx +11 -0
- package/resourceViews/RawCode/RawCodeEditor.tsx +37 -0
- package/resourceViews/RawCode/RawCodeView.tsx +67 -0
- package/scripts/adjust-server-paths.js +37 -0
- package/scripts/adjust-standalone-paths.js +28 -0
- package/tailwind.config.js +69 -0
- package/test-server/server-config.json +75 -0
- package/test-server/solid-css-seed.json +11 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { LucideIcon } from 'lucide-react-native';
|
|
2
|
+
import { cssInterop } from 'nativewind';
|
|
3
|
+
|
|
4
|
+
export function iconWithClassName(icon: LucideIcon) {
|
|
5
|
+
cssInterop(icon, {
|
|
6
|
+
className: {
|
|
7
|
+
target: 'style',
|
|
8
|
+
nativeStyleToProp: {
|
|
9
|
+
color: true,
|
|
10
|
+
opacity: true,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
}
|
package/lib/utils.ts
ADDED
package/metro.config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="nativewind/types" />
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "linked-data-browser",
|
|
3
|
+
"main": "index.js",
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev:ios": "expo start -c --ios",
|
|
7
|
+
"dev:web": "concurrently \"npm run solid-server\" \"expo start -c --web\"",
|
|
8
|
+
"dev:android": "expo start -c --android",
|
|
9
|
+
"dev:server-hosted": "concurrently \"npm run solid-server\" \"npm run build:server:watch\"",
|
|
10
|
+
"clean": "rm -rf .expo node_modules dist-standalone dist-server",
|
|
11
|
+
"postinstall": "npx tailwindcss -i ./global.css -o ./node_modules/.cache/nativewind/global.css",
|
|
12
|
+
"build:standalone": "expo export -p web --output-dir dist-standalone && node scripts/adjust-standalone-paths.js",
|
|
13
|
+
"build:server": "EXPO_PUBLIC_IS_SERVER_HOSTED=true expo export -p web --output-dir dist-server && node scripts/adjust-server-paths.js",
|
|
14
|
+
"build:server:watch": "npx chokidar '**/*' -i 'dist-standalone/**' -i 'dist-server/**' -i 'node_modules/**' -c 'npm run build:server'",
|
|
15
|
+
"solid-server": "community-solid-server -c ./test-server/server-config.json -f ./data --seed-config ./test-server/solid-css-seed.json",
|
|
16
|
+
"build:ldo": "ldo build --input .shapes --output .ldo",
|
|
17
|
+
"build": "npm run build:standalone && npm run build:server"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@inrupt/solid-client-authn-browser": "^2.5.0",
|
|
21
|
+
"@ldo/connected-solid": "^1.0.0-alpha.26",
|
|
22
|
+
"@ldo/ldo": "^1.0.0-alpha.21",
|
|
23
|
+
"@ldo/solid-react": "^1.0.0-alpha.26",
|
|
24
|
+
"@monaco-editor/react": "^4.7.0",
|
|
25
|
+
"@radix-ui/react-dialog": "^1.1.14",
|
|
26
|
+
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
|
27
|
+
"@radix-ui/react-label": "^2.1.7",
|
|
28
|
+
"@radix-ui/react-navigation-menu": "^1.2.13",
|
|
29
|
+
"@radix-ui/react-popover": "^1.1.14",
|
|
30
|
+
"@radix-ui/react-progress": "^1.1.7",
|
|
31
|
+
"@radix-ui/react-radio-group": "^1.3.7",
|
|
32
|
+
"@radix-ui/react-switch": "^1.2.5",
|
|
33
|
+
"@radix-ui/react-tooltip": "^1.2.7",
|
|
34
|
+
"@react-native-async-storage/async-storage": "2.1.2",
|
|
35
|
+
"@react-navigation/native": "^7.1.14",
|
|
36
|
+
"@rn-primitives/avatar": "~1.2.0",
|
|
37
|
+
"@rn-primitives/dialog": "^1.2.0",
|
|
38
|
+
"@rn-primitives/dropdown-menu": "^1.2.0",
|
|
39
|
+
"@rn-primitives/label": "^1.2.0",
|
|
40
|
+
"@rn-primitives/navigation-menu": "^1.2.0",
|
|
41
|
+
"@rn-primitives/popover": "^1.2.0",
|
|
42
|
+
"@rn-primitives/portal": "~1.3.0",
|
|
43
|
+
"@rn-primitives/progress": "~1.2.0",
|
|
44
|
+
"@rn-primitives/radio-group": "^1.2.0",
|
|
45
|
+
"@rn-primitives/separator": "^1.2.0",
|
|
46
|
+
"@rn-primitives/slot": "~1.2.0",
|
|
47
|
+
"@rn-primitives/switch": "^1.2.0",
|
|
48
|
+
"@rn-primitives/tooltip": "~1.2.0",
|
|
49
|
+
"class-variance-authority": "^0.7.0",
|
|
50
|
+
"clsx": "^2.1.0",
|
|
51
|
+
"constate": "^3.3.3",
|
|
52
|
+
"expo": "^53.0.9",
|
|
53
|
+
"expo-linking": "~7.1.5",
|
|
54
|
+
"expo-navigation-bar": "~4.2.4",
|
|
55
|
+
"expo-splash-screen": "~0.30.8",
|
|
56
|
+
"expo-status-bar": "~2.2.3",
|
|
57
|
+
"expo-system-ui": "~5.0.7",
|
|
58
|
+
"lucide-react-native": "^0.511.0",
|
|
59
|
+
"nativewind": "^4.1.23",
|
|
60
|
+
"react": "19.0.0",
|
|
61
|
+
"react-dom": "19.0.0",
|
|
62
|
+
"react-native": "0.79.2",
|
|
63
|
+
"react-native-notifier": "^2.0.0",
|
|
64
|
+
"react-native-reanimated": "~3.17.5",
|
|
65
|
+
"react-native-safe-area-context": "^5.4.0",
|
|
66
|
+
"react-native-screens": "~4.10.0",
|
|
67
|
+
"react-native-svg": "15.11.2",
|
|
68
|
+
"react-native-web": "~0.20.0",
|
|
69
|
+
"tailwind-merge": "^2.2.1",
|
|
70
|
+
"tailwindcss": "3.3.5",
|
|
71
|
+
"tailwindcss-animate": "^1.0.7"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@babel/core": "^7.26.0",
|
|
75
|
+
"@ldo/cli": "^1.0.0-alpha.21",
|
|
76
|
+
"@react-native-community/eslint-config": "^3.2.0",
|
|
77
|
+
"@solid/community-server": "^7.1.7",
|
|
78
|
+
"@types/jsonld": "^1.5.15",
|
|
79
|
+
"@types/react": "~19.0.14",
|
|
80
|
+
"@types/shexj": "^2.1.7",
|
|
81
|
+
"chokidar-cli": "^3.0.0",
|
|
82
|
+
"concurrently": "^9.1.2",
|
|
83
|
+
"eslint-config-prettier": "^10.1.5",
|
|
84
|
+
"eslint-plugin-prettier": "^5.4.1",
|
|
85
|
+
"prettier": "^3.5.3",
|
|
86
|
+
"typescript": "^5.8.3"
|
|
87
|
+
},
|
|
88
|
+
"private": false
|
|
89
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ResourceViewConfig } from '~/components/ResourceView';
|
|
2
|
+
import { Folders } from '~/lib/icons/Folders';
|
|
3
|
+
import { ContainerView } from './ContainerView';
|
|
4
|
+
|
|
5
|
+
export const ContainerConfig: ResourceViewConfig = {
|
|
6
|
+
name: 'container',
|
|
7
|
+
displayName: 'Container',
|
|
8
|
+
displayIcon: Folders,
|
|
9
|
+
view: ContainerView,
|
|
10
|
+
canDisplay: (targetUri, targetResource) => {
|
|
11
|
+
return targetResource.type === 'SolidContainer';
|
|
12
|
+
},
|
|
13
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import React, { FunctionComponent, useCallback } from 'react';
|
|
2
|
+
import { View, FlatList, TouchableWithoutFeedback } from 'react-native';
|
|
3
|
+
import { Text } from '~/components/ui/text';
|
|
4
|
+
import { Button } from '~/components/ui/button';
|
|
5
|
+
import {
|
|
6
|
+
DropdownMenu,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
DropdownMenuContent,
|
|
9
|
+
DropdownMenuItem,
|
|
10
|
+
} from '~/components/ui/dropdown-menu';
|
|
11
|
+
import { useTargetResource } from '~/components/TargetResourceProvider';
|
|
12
|
+
import { ErrorMessageResourceView } from '~/components/nav/utilityResourceViews/ErrorMessageResourceView';
|
|
13
|
+
import { CircleX } from '~/lib/icons/CircleX';
|
|
14
|
+
import { Folder } from '~/lib/icons/Folder';
|
|
15
|
+
import { Code } from '~/lib/icons/Code';
|
|
16
|
+
import { File } from '~/lib/icons/File';
|
|
17
|
+
import { Trash } from '~/lib/icons/Trash';
|
|
18
|
+
import { Separator } from '~/components/ui/separator';
|
|
19
|
+
import { useDialog } from '~/components/nav/DialogProvider';
|
|
20
|
+
import {
|
|
21
|
+
SolidContainer,
|
|
22
|
+
SolidContainerSlug,
|
|
23
|
+
SolidLeaf,
|
|
24
|
+
} from '@ldo/connected-solid';
|
|
25
|
+
import { Notifier } from 'react-native-notifier';
|
|
26
|
+
|
|
27
|
+
export const ContainerView: FunctionComponent = () => {
|
|
28
|
+
const { targetResource, navigateTo } = useTargetResource();
|
|
29
|
+
const { prompt } = useDialog();
|
|
30
|
+
|
|
31
|
+
const onCreateContainer = useCallback(async () => {
|
|
32
|
+
if (targetResource?.type !== 'SolidContainer') return;
|
|
33
|
+
const givenName = await prompt('Enter Container Name');
|
|
34
|
+
if (!givenName) return;
|
|
35
|
+
const slug = (
|
|
36
|
+
givenName.endsWith('/') ? givenName : `${givenName}/`
|
|
37
|
+
) as SolidContainerSlug;
|
|
38
|
+
const createResult = await targetResource.createChildIfAbsent(slug);
|
|
39
|
+
if (createResult.isError)
|
|
40
|
+
Notifier.showNotification({ title: createResult.message });
|
|
41
|
+
if (createResult.type === 'containerReadSuccess')
|
|
42
|
+
Notifier.showNotification({ title: `${slug} already exists.` });
|
|
43
|
+
}, [prompt, targetResource]);
|
|
44
|
+
|
|
45
|
+
const onCreateRdf = useCallback(async () => {
|
|
46
|
+
if (targetResource?.type !== 'SolidContainer') return;
|
|
47
|
+
const givenName = await prompt('Enter File Name');
|
|
48
|
+
if (!givenName) return;
|
|
49
|
+
const slug = (
|
|
50
|
+
givenName.endsWith('.ttl') ? givenName : `${givenName}.ttl`
|
|
51
|
+
) as SolidContainerSlug;
|
|
52
|
+
const createResult = await targetResource.createChildIfAbsent(slug);
|
|
53
|
+
if (createResult.isError)
|
|
54
|
+
Notifier.showNotification({ title: createResult.message });
|
|
55
|
+
if (createResult.type === 'containerReadSuccess')
|
|
56
|
+
Notifier.showNotification({ title: `${slug} already exists.` });
|
|
57
|
+
}, [prompt, targetResource]);
|
|
58
|
+
|
|
59
|
+
const onUpload = useCallback(async () => {
|
|
60
|
+
if (targetResource?.type !== 'SolidContainer') return;
|
|
61
|
+
// Not Implemented
|
|
62
|
+
Notifier.showNotification({ title: 'Not Implemented' });
|
|
63
|
+
}, [targetResource?.type]);
|
|
64
|
+
|
|
65
|
+
const onDelete = useCallback(
|
|
66
|
+
async (item: SolidLeaf | SolidContainer) => {
|
|
67
|
+
if (targetResource?.type !== 'SolidContainer') return;
|
|
68
|
+
const createResult = await item.delete();
|
|
69
|
+
if (createResult.isError)
|
|
70
|
+
Notifier.showNotification({ title: createResult.message });
|
|
71
|
+
},
|
|
72
|
+
[targetResource?.type],
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (targetResource?.type !== 'SolidContainer') {
|
|
76
|
+
return (
|
|
77
|
+
<ErrorMessageResourceView
|
|
78
|
+
icon={CircleX}
|
|
79
|
+
message="The target resource is not a container"
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<View className="flex-1 flex-row">
|
|
86
|
+
{/* Left Panel */}
|
|
87
|
+
<View className="max-w-[200px] flex-1 p-4">
|
|
88
|
+
<DropdownMenu>
|
|
89
|
+
<DropdownMenuTrigger asChild>
|
|
90
|
+
<Button>
|
|
91
|
+
<Text>Create</Text>
|
|
92
|
+
</Button>
|
|
93
|
+
</DropdownMenuTrigger>
|
|
94
|
+
<DropdownMenuContent>
|
|
95
|
+
<DropdownMenuItem onPress={onCreateContainer}>
|
|
96
|
+
<Text>Container</Text>
|
|
97
|
+
</DropdownMenuItem>
|
|
98
|
+
<DropdownMenuItem onPress={onCreateRdf}>
|
|
99
|
+
<Text>RDF Turtle</Text>
|
|
100
|
+
</DropdownMenuItem>
|
|
101
|
+
<DropdownMenuItem onPress={onUpload}>
|
|
102
|
+
<Text>File Upload</Text>
|
|
103
|
+
</DropdownMenuItem>
|
|
104
|
+
</DropdownMenuContent>
|
|
105
|
+
</DropdownMenu>
|
|
106
|
+
</View>
|
|
107
|
+
|
|
108
|
+
{/* Right Panel */}
|
|
109
|
+
<View className="flex-[3] py-4 pr-4">
|
|
110
|
+
<FlatList
|
|
111
|
+
data={targetResource.children()}
|
|
112
|
+
keyExtractor={(item) => item.uri}
|
|
113
|
+
renderItem={({ item, index }) => {
|
|
114
|
+
const Icon =
|
|
115
|
+
item.type === 'SolidContainer'
|
|
116
|
+
? Folder
|
|
117
|
+
: item.uri.endsWith('.ttl')
|
|
118
|
+
? Code
|
|
119
|
+
: File;
|
|
120
|
+
return (
|
|
121
|
+
<>
|
|
122
|
+
{index === 0 && <Separator />}
|
|
123
|
+
<TouchableWithoutFeedback onPress={() => navigateTo(item.uri)}>
|
|
124
|
+
<View className="flex flex-row p-4 hover:bg-secondary rounded-sm cursor-pointer justify-between">
|
|
125
|
+
<Text className="flex flex-row gap-3">
|
|
126
|
+
<Icon />
|
|
127
|
+
{item.uri.replace(targetResource.uri, '')}
|
|
128
|
+
</Text>
|
|
129
|
+
<Button
|
|
130
|
+
variant="ghost"
|
|
131
|
+
className="h-6 p-0"
|
|
132
|
+
onPress={() => onDelete(item)}
|
|
133
|
+
>
|
|
134
|
+
<Text>
|
|
135
|
+
<Trash size={20} />
|
|
136
|
+
</Text>
|
|
137
|
+
</Button>
|
|
138
|
+
</View>
|
|
139
|
+
</TouchableWithoutFeedback>
|
|
140
|
+
<Separator />
|
|
141
|
+
</>
|
|
142
|
+
);
|
|
143
|
+
}}
|
|
144
|
+
/>
|
|
145
|
+
</View>
|
|
146
|
+
</View>
|
|
147
|
+
);
|
|
148
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ResourceViewConfig } from '~/components/ResourceView';
|
|
2
|
+
import { Code } from '~/lib/icons/Code';
|
|
3
|
+
import { RawCodeView } from './RawCodeView';
|
|
4
|
+
|
|
5
|
+
export const RawCodeConfig: ResourceViewConfig = {
|
|
6
|
+
name: 'rawCode',
|
|
7
|
+
displayName: 'Raw Code',
|
|
8
|
+
displayIcon: Code,
|
|
9
|
+
view: RawCodeView,
|
|
10
|
+
canDisplay: () => true,
|
|
11
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React, { FunctionComponent, useRef } from 'react';
|
|
2
|
+
import { Text } from '~/components/ui/text';
|
|
3
|
+
import Editor, { Monaco, OnMount } from '@monaco-editor/react';
|
|
4
|
+
import { useThemeChange } from '~/components/ThemeProvider';
|
|
5
|
+
|
|
6
|
+
interface RawCodeEditorProps {
|
|
7
|
+
value: string;
|
|
8
|
+
onChange: (value: string | undefined) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const RawCodeEditor: FunctionComponent<RawCodeEditorProps> = ({
|
|
12
|
+
value,
|
|
13
|
+
onChange,
|
|
14
|
+
}) => {
|
|
15
|
+
const monacoRef = useRef<Monaco>(null);
|
|
16
|
+
const { colorScheme } = useThemeChange();
|
|
17
|
+
|
|
18
|
+
function handleEditorWillMount(monaco: Monaco) {
|
|
19
|
+
monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const handleEditorDidMount: OnMount = (editor, monaco) => {
|
|
23
|
+
monacoRef.current = monaco;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Editor
|
|
28
|
+
className="flex-1"
|
|
29
|
+
defaultLanguage="turtle"
|
|
30
|
+
theme={colorScheme === 'light' ? 'light' : 'hc-black'}
|
|
31
|
+
value={value}
|
|
32
|
+
onChange={onChange}
|
|
33
|
+
beforeMount={handleEditorWillMount}
|
|
34
|
+
onMount={handleEditorDidMount}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useSolidAuth } from '@ldo/solid-react';
|
|
2
|
+
import React, {
|
|
3
|
+
FunctionComponent,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
8
|
+
import { useTargetResource } from '~/components/TargetResourceProvider';
|
|
9
|
+
import { RawCodeEditor } from './RawCodeEditor';
|
|
10
|
+
import { View } from 'react-native';
|
|
11
|
+
import { Button } from '~/components/ui/button';
|
|
12
|
+
import { Text } from '~/components/ui/text';
|
|
13
|
+
import { Notifier } from 'react-native-notifier';
|
|
14
|
+
|
|
15
|
+
export const RawCodeView: FunctionComponent = () => {
|
|
16
|
+
const { targetUri } = useTargetResource();
|
|
17
|
+
const { fetch } = useSolidAuth();
|
|
18
|
+
const [content, setContent] = useState<string>('');
|
|
19
|
+
|
|
20
|
+
// Independently fetch the target resource, so we have the raw turtle
|
|
21
|
+
const fetchContent = useCallback(async () => {
|
|
22
|
+
if (!targetUri) return;
|
|
23
|
+
const response = await fetch(targetUri);
|
|
24
|
+
if (response.status !== 200) {
|
|
25
|
+
Notifier.showNotification({
|
|
26
|
+
title: `Could not fetch document. Recieved ${response.status}`,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
setContent(await response.text());
|
|
30
|
+
}, [fetch, targetUri]);
|
|
31
|
+
|
|
32
|
+
const submitChanges = useCallback(async () => {
|
|
33
|
+
if (!targetUri) return;
|
|
34
|
+
const response = await fetch(targetUri, {
|
|
35
|
+
method: 'put',
|
|
36
|
+
body: content,
|
|
37
|
+
});
|
|
38
|
+
if (response.status !== 205) {
|
|
39
|
+
Notifier.showNotification({
|
|
40
|
+
title: `Could save document. Recieved ${response.status}`,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
Notifier.showNotification({
|
|
44
|
+
title: `Document Saved`,
|
|
45
|
+
});
|
|
46
|
+
await fetchContent();
|
|
47
|
+
}, [content, fetch, fetchContent, targetUri]);
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
fetchContent();
|
|
51
|
+
}, [fetchContent]);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<View className="flex-1 relative">
|
|
55
|
+
<RawCodeEditor
|
|
56
|
+
value={content}
|
|
57
|
+
onChange={(value) => setContent(value ?? '')}
|
|
58
|
+
/>
|
|
59
|
+
<Button
|
|
60
|
+
className="absolute bottom-2 right-2 z-10"
|
|
61
|
+
onPress={submitChanges}
|
|
62
|
+
>
|
|
63
|
+
<Text>Save Changes</Text>
|
|
64
|
+
</Button>
|
|
65
|
+
</View>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// scripts/adjust-server-paths.js
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const indexHtmlPath = path.join(__dirname, '../dist-server/index.html');
|
|
6
|
+
|
|
7
|
+
fs.readFile(indexHtmlPath, 'utf8', (err, data) => {
|
|
8
|
+
if (err) {
|
|
9
|
+
console.error('Error reading index.html:', err);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Regex to prefix all root-relative href and src paths,
|
|
14
|
+
// unless they already contain '/.ui-static/'
|
|
15
|
+
let modifiedData = data.replace(
|
|
16
|
+
/(href|src)=["'](\/(?!\.ui-static\/)\S*?)["']/g,
|
|
17
|
+
(match, attr, urlPath) => {
|
|
18
|
+
return `${attr}="/.ui-static${urlPath}"`;
|
|
19
|
+
},
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
// Modify the hydration flag for server-hosted build to false
|
|
23
|
+
modifiedData = modifiedData.replace(
|
|
24
|
+
/globalThis\.__EXPO_ROUTER_HYDRATE__=true;/,
|
|
25
|
+
'globalThis.__EXPO_ROUTER_HYDRATE__=false;',
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
fs.writeFile(indexHtmlPath, modifiedData, 'utf8', (err2) => {
|
|
29
|
+
if (err2) {
|
|
30
|
+
console.error('Error writing index.html:', err2);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
console.log(
|
|
34
|
+
'Successfully adjusted paths and hydration flag in dist-server/index.html',
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// scripts/adjust-server-paths.js
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const indexHtmlPath = path.join(__dirname, '../dist-standalone/index.html');
|
|
6
|
+
|
|
7
|
+
fs.readFile(indexHtmlPath, 'utf8', (err, data) => {
|
|
8
|
+
if (err) {
|
|
9
|
+
console.error('Error reading index.html:', err);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Modify the hydration flag for server-hosted build to false
|
|
14
|
+
let modifiedData = data.replace(
|
|
15
|
+
/globalThis\.__EXPO_ROUTER_HYDRATE__=true;/,
|
|
16
|
+
'globalThis.__EXPO_ROUTER_HYDRATE__=false;',
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
fs.writeFile(indexHtmlPath, modifiedData, 'utf8', (err2) => {
|
|
20
|
+
if (err2) {
|
|
21
|
+
console.error('Error writing index.html:', err2);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
console.log(
|
|
25
|
+
'Successfully adjusted hydration flag in dist-standalone/index.html',
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const { hairlineWidth } = require('nativewind/theme');
|
|
2
|
+
|
|
3
|
+
/** @type {import('tailwindcss').Config} */
|
|
4
|
+
module.exports = {
|
|
5
|
+
darkMode: 'class',
|
|
6
|
+
content: [
|
|
7
|
+
'./app/**/*.{ts,tsx}',
|
|
8
|
+
'./components/**/*.{ts,tsx}',
|
|
9
|
+
'./resourceViews/**/*.{ts,tsx}',
|
|
10
|
+
],
|
|
11
|
+
presets: [require('nativewind/preset')],
|
|
12
|
+
theme: {
|
|
13
|
+
extend: {
|
|
14
|
+
colors: {
|
|
15
|
+
border: 'hsl(var(--border))',
|
|
16
|
+
input: 'hsl(var(--input))',
|
|
17
|
+
ring: 'hsl(var(--ring))',
|
|
18
|
+
background: 'hsl(var(--background))',
|
|
19
|
+
foreground: 'hsl(var(--foreground))',
|
|
20
|
+
primary: {
|
|
21
|
+
DEFAULT: 'hsl(var(--primary))',
|
|
22
|
+
foreground: 'hsl(var(--primary-foreground))',
|
|
23
|
+
},
|
|
24
|
+
secondary: {
|
|
25
|
+
DEFAULT: 'hsl(var(--secondary))',
|
|
26
|
+
foreground: 'hsl(var(--secondary-foreground))',
|
|
27
|
+
},
|
|
28
|
+
destructive: {
|
|
29
|
+
DEFAULT: 'hsl(var(--destructive))',
|
|
30
|
+
foreground: 'hsl(var(--destructive-foreground))',
|
|
31
|
+
},
|
|
32
|
+
muted: {
|
|
33
|
+
DEFAULT: 'hsl(var(--muted))',
|
|
34
|
+
foreground: 'hsl(var(--muted-foreground))',
|
|
35
|
+
},
|
|
36
|
+
accent: {
|
|
37
|
+
DEFAULT: 'hsl(var(--accent))',
|
|
38
|
+
foreground: 'hsl(var(--accent-foreground))',
|
|
39
|
+
},
|
|
40
|
+
popover: {
|
|
41
|
+
DEFAULT: 'hsl(var(--popover))',
|
|
42
|
+
foreground: 'hsl(var(--popover-foreground))',
|
|
43
|
+
},
|
|
44
|
+
card: {
|
|
45
|
+
DEFAULT: 'hsl(var(--card))',
|
|
46
|
+
foreground: 'hsl(var(--card-foreground))',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
borderWidth: {
|
|
50
|
+
hairline: hairlineWidth(),
|
|
51
|
+
},
|
|
52
|
+
keyframes: {
|
|
53
|
+
'accordion-down': {
|
|
54
|
+
from: { height: '0' },
|
|
55
|
+
to: { height: 'var(--radix-accordion-content-height)' },
|
|
56
|
+
},
|
|
57
|
+
'accordion-up': {
|
|
58
|
+
from: { height: 'var(--radix-accordion-content-height)' },
|
|
59
|
+
to: { height: '0' },
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
animation: {
|
|
63
|
+
'accordion-down': 'accordion-down 0.2s ease-out',
|
|
64
|
+
'accordion-up': 'accordion-up 0.2s ease-out',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
plugins: [require('tailwindcss-animate')],
|
|
69
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"@context": [
|
|
3
|
+
"https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^7.0.0/components/context.jsonld"
|
|
4
|
+
],
|
|
5
|
+
"import": [
|
|
6
|
+
"css:config/app/init/default.json",
|
|
7
|
+
"css:config/app/main/default.json",
|
|
8
|
+
"css:config/app/variables/default.json",
|
|
9
|
+
"css:config/http/handler/default.json",
|
|
10
|
+
"css:config/http/middleware/default.json",
|
|
11
|
+
"css:config/http/notifications/all.json",
|
|
12
|
+
"css:config/http/server-factory/http.json",
|
|
13
|
+
"css:config/http/static/default.json",
|
|
14
|
+
"css:config/identity/access/public.json",
|
|
15
|
+
"css:config/identity/email/default.json",
|
|
16
|
+
"css:config/identity/handler/default.json",
|
|
17
|
+
"css:config/identity/oidc/default.json",
|
|
18
|
+
"css:config/identity/ownership/token.json",
|
|
19
|
+
"css:config/identity/pod/static.json",
|
|
20
|
+
"css:config/ldp/authentication/dpop-bearer.json",
|
|
21
|
+
"css:config/ldp/authorization/webacl.json",
|
|
22
|
+
"css:config/ldp/handler/default.json",
|
|
23
|
+
"css:config/ldp/metadata-parser/default.json",
|
|
24
|
+
"css:config/ldp/metadata-writer/default.json",
|
|
25
|
+
"css:config/ldp/modes/default.json",
|
|
26
|
+
"css:config/storage/backend/file.json",
|
|
27
|
+
"css:config/storage/key-value/resource-store.json",
|
|
28
|
+
"css:config/storage/location/pod.json",
|
|
29
|
+
"css:config/storage/middleware/default.json",
|
|
30
|
+
"css:config/util/auxiliary/acl.json",
|
|
31
|
+
"css:config/util/identifiers/suffix.json",
|
|
32
|
+
"css:config/util/logging/winston.json",
|
|
33
|
+
"css:config/util/representation-conversion/default.json",
|
|
34
|
+
"css:config/util/resource-locker/file.json",
|
|
35
|
+
"css:config/util/variables/default.json"
|
|
36
|
+
],
|
|
37
|
+
"@graph": [
|
|
38
|
+
{
|
|
39
|
+
"comment": "A Solid server that stores its resources on disk and uses WAC for authorization."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"comment": "Serve Linked-Data-Browser as default representation",
|
|
43
|
+
"@id": "urn:solid-server:default:DefaultUiConverter",
|
|
44
|
+
"@type": "ConstantConverter",
|
|
45
|
+
"contentType": "text/html",
|
|
46
|
+
"filePath": "./dist-server/index.html",
|
|
47
|
+
"options_container": true,
|
|
48
|
+
"options_document": true,
|
|
49
|
+
"options_minQuality": 1
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"@type": "Override",
|
|
53
|
+
"overrideInstance": {
|
|
54
|
+
"@type": "StaticAssetEntry",
|
|
55
|
+
"@id": "urn:solid-server:default:RootStaticAsset"
|
|
56
|
+
},
|
|
57
|
+
"overrideParameters": {
|
|
58
|
+
"@type": "StaticAssetEntry",
|
|
59
|
+
"filePath": "./dist-server/index.html"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"comment": "Serve Linked-Data-Browser static files.",
|
|
64
|
+
"@id": "urn:solid-server:default:StaticAssetHandler",
|
|
65
|
+
"@type": "StaticAssetHandler",
|
|
66
|
+
"assets": [
|
|
67
|
+
{
|
|
68
|
+
"@type": "StaticAssetEntry",
|
|
69
|
+
"relativeUrl": "/.ui-static/",
|
|
70
|
+
"filePath": "./dist-server/"
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "expo/tsconfig.base",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"strict": true,
|
|
5
|
+
"baseUrl": ".",
|
|
6
|
+
"paths": {
|
|
7
|
+
"~/*": [
|
|
8
|
+
"*"
|
|
9
|
+
]
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"include": [
|
|
13
|
+
"**/*.ts",
|
|
14
|
+
"**/*.tsx",
|
|
15
|
+
".expo/types/**/*.ts",
|
|
16
|
+
"expo-env.d.ts",
|
|
17
|
+
"nativewind-env.d.ts"
|
|
18
|
+
]
|
|
19
|
+
}
|