Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.{bat,cmd}]
end_of_line = crlf
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Default line ending
* text=auto eol=lf

# Windows files
*.bat text eol=crlf
72 changes: 40 additions & 32 deletions client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,60 +8,53 @@
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
/>
<meta name="mobile-web-app-capable" content="yes">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://rsms.me/" />
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&display=swap" rel="stylesheet">
<title>__APP_NAME__</title>
<style>
:root {
font-family: __FONT_NAME__, sans-serif;
font-family: '__FONT_NAME__', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-feature-settings:
"liga" 1,
"calt" 1;
--bg: #fff;
--bg-dark: #09090b;
--sel: rgba(0, 0, 0, 0.2);
--sel-dark: rgba(255, 255, 255, 0.2);
}

a:-webkit-any-link {
cursor: default;
body.dark {
--bg: var(--bg-dark);
--sel: var(--sel-dark);
}

*:focus {
outline: none;
@media (prefers-color-scheme: dark) {
:root {
--bg: var(--bg-dark);
--sel: var(--sel-dark);
}
}

@media (prefers-reduced-motion: no-preference) {
html {
scroll-behavior: smooth;
}
}

*:focus {outline: none}
::selection {background: var(--sel)}
a:-webkit-any-link {cursor: default}

html,
body,
#root {
height: 100%;
width: 100%;
margin: 0;
display: flex;
background: #fff;
background: var(--bg);
overscroll-behavior: none;
overflow: hidden;
}

@media (prefers-color-scheme: dark) {
html,
body,
#root {
background: #000;
}
}

@supports (font-variation-settings: normal) {
:root {
font-family: __FONT_NAME__Variable, sans-serif;
}
}

@media (prefers-reduced-motion: no-preference) {
html {
scroll-behavior: smooth;
}
}

/* PointerEvent */
._p {
cursor: default;
Expand All @@ -85,7 +78,6 @@
/* Zeego */
.ContextMenuContent,
.ContextMenuSubContent {
width: 200px;
background-color: #09090b;
border: 1px solid #27272a;
border-radius: 6px;
Expand All @@ -94,6 +86,22 @@
box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 2px 1px
}

.ContextMenuContent.context {
width: 200px;
}

.ContextMenuArrow {
fill: #27272a;
}

.ContextMenuTrigger {
padding: 0;
cursor: default;
border: none;
outline: none;
background: none;
}

.ContextMenuLabel {
margin: -5px;
margin-bottom: 5px;
Expand Down
106 changes: 48 additions & 58 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@
"android": "react-native run-android --no-packager",
"ios": "react-native run-ios --no-packager",
"macos": "react-native run-macos --no-packager --scheme FOV",
"visionos": "react-native run-visionos --no-packager",
"windows": "react-native run-windows --no-packager",
"build:web": "vite build",
"_build:android": "react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist/res",
"_build:ios": "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist",
"_build:macos": "react-native bundle --entry-file index.js --platform macos --dev true --bundle-output dist/main.macos.jsbundle --assets-dest dist",
"_build:visionos": "react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.visionos.jsbundle --assets-dest dist",
"_build:windows": "react-native bundle --entry-file index.js --platform windows --dev true --bundle-output dist/main.windows.bundle --assets-dest dist",
"start:web": "vite dev --port 6206 --host",
"start:native": "react-native rnx-start --reset-cache",
Expand All @@ -24,103 +22,95 @@
"_postinstall": "pnpm generate:*"
},
"dependencies": {
"@ai-sdk/openai": "^1.0.11",
"@atlaskit/pragmatic-drag-and-drop": "^1.4.0",
"@callstack/react-native-visionos": "^0.76.2",
"@ai-sdk/openai": "^1.3.23",
"@atlaskit/pragmatic-drag-and-drop": "^1.7.4",
"@candlefinance/faster-image": "^1.7.2",
"@effect/platform": "0.69.9",
"@effect/platform": "0.69.31",
"@effect/schema": "0.75.5",
"@evolu/common": "^5.4.8",
"@evolu/common-web": "^8.2.4",
"@evolu/react": "^8.2.2",
"@evolu/react-native": "^11.1.2",
"@helia/verified-fetch": "^2.3.1",
"@legendapp/list": "1.0.0-beta.8",
"@helia/verified-fetch": "^3.2.0",
"@legendapp/list": "1.1.4",
"@lingui/core": "^5.2.0",
"@lingui/macro": "^5.2.0",
"@lingui/react": "^5.2.0",
"@marceloterreiro/flash-calendar": "^1.3.0",
"@noriginmedia/norigin-spatial-navigation": "^2.2.3",
"@react-native-community/checkbox": "^0.5.17",
"@noriginmedia/norigin-spatial-navigation": "^2.3.0",
"@react-native-community/checkbox": "^0.5.20",
"@react-native-community/geolocation": "^3.4.0",
"@react-native-community/netinfo": "^11.4.1",
"@react-native-community/slider": "^4.5.5",
"@react-native-picker/picker": "^2.10.2",
"@shopify/flash-list": "1.6.3",
"@shopify/react-native-skia": "1.8.0",
"@zip.js/zip.js": "^2.7.54",
"ai": "^4.0.22",
"blo": "^1.2.0",
"burnt": "^0.12.2",
"@react-native-community/slider": "^4.5.7",
"@react-native-picker/picker": "^2.11.1",
"@shopify/react-native-skia": "2.1.1",
"@zip.js/zip.js": "^2.7.64",
"ai": "^4.3.19",
"blo": "^2.0.0",
"burnt": "^0.13.0",
"design": "workspace:react-exo-ui@*",
"effect": "3.10.4",
"file-type": "^19.6.0",
"maplibre-gl": "4.7.1",
"matrix-js-sdk": "^36.0.0",
"openmeteo": "^1.1.4",
"file-type": "^21.0.0",
"maplibre-gl": "5.6.1",
"matrix-js-sdk": "^37.11.0",
"openmeteo": "^1.2.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-exo": "0.18.27",
"react-exo": "0.18.37",
"react-exo-ui": "workspace:*",
"react-map-gl": "^7.1.8",
"react-native": "^0.76.5",
"react-native-bootsplash": "^6.3.2",
"react-native-gesture-handler": "^2.21.2",
"react-native-ios-context-menu": "^2.5.3",
"react-map-gl": "^8.0.4",
"react-native": "^0.78.3",
"react-native-bootsplash": "^6.3.10",
"react-native-gesture-handler": "^2.27.1",
"react-native-ios-context-menu": "^3.1.2",
"react-native-linear-gradient": "^2.8.3",
"react-native-macos": "^0.76.6",
"react-native-mmkv": "^3.2.0",
"react-native-navigation": "7.40.3",
"react-native-mmkv": "^3.3.0",
"react-native-qrcode-skia": "^0.3.1",
"react-native-random-values-jsi-helper": "^2.0.1",
"react-native-readium": "^2.0.2",
"react-native-reanimated": "^3.16.6",
"react-native-screens": "^4.4.0",
"react-native-readium": "^3.0.2",
"react-native-reanimated": "^3.18.0",
"react-native-screens": "^4.13.1",
"react-native-skottie": "^2.1.4",
"react-native-svg": "^15.10.1",
"react-native-svg": "^15.12.0",
"react-native-svg-app-icon": "^0.6.1",
"react-native-svg-transformer": "^1.5.0",
"react-native-svg-transformer": "^1.5.1",
"react-native-unistyles": "^2.20.0",
"react-native-url-polyfill": "^2.0.0",
"react-native-video": "^6.8.2",
"react-native-video": "^6.16.1",
"react-native-web": "^0.19.13",
"react-native-web-linear-gradient": "^1.1.2",
"react-native-windows": "0.76.3",
"react-native-zoom-toolkit": "^4.0.0",
"react-scan": "^0.1.3",
"react-zoom-pan-pinch": "^3.6.1",
"recyclerlistview": "4.2.1",
"rive-react-native": "^8.3.0",
"react-native-zoom-toolkit": "^5.0.0",
"react-scan": "^0.4.3",
"react-zoom-pan-pinch": "^3.7.0",
"rive-react-native": "^9.3.4",
"rmapi-js": "^8.3.0",
"uint8array-extras": "^1.4.0",
"vite-plugin-node-polyfills": "^0.22.0",
"webtorrent": "^2.5.11",
"vite-plugin-node-polyfills": "^0.24.0",
"webtorrent": "^2.6.10",
"zeego": "^2.0.4"
},
"devDependencies": {
"@babel/core": "^7.26.0",
"@babel/preset-env": "^7.26.0",
"@babel/runtime": "^7.26.0",
"@react-native/babel-preset": "0.76.5",
"@react-native/metro-config": "0.76.5",
"@babel/core": "^7.28.0",
"@babel/preset-env": "^7.28.0",
"@babel/runtime": "^7.27.6",
"@react-native/babel-preset": "0.80.1",
"@react-native/metro-config": "0.80.1",
"@rnx-kit/babel-preset-metro-react-native": "^2.0.0",
"@rnx-kit/cli": "^0.18.4",
"@rnx-kit/metro-config": "^2.0.1",
"@rnx-kit/cli": "^0.18.9",
"@rnx-kit/metro-config": "^2.1.0",
"@rnx-kit/metro-plugin-duplicates-checker": "^3.0.0",
"@rnx-kit/metro-plugin-typescript": "^0.5.1",
"@rnx-kit/metro-resolver-symlinks": "^0.2.1",
"@types/babel__core": "^7.20.5",
"@rnx-kit/metro-resolver-symlinks": "^0.2.5",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@types/react-test-renderer": "^18.3.1",
"@types/webtorrent": "^0.110.0",
"babel-plugin-macros": "^3.1.0",
"babel-plugin-tsconfig-paths-module-resolver": "^1.0.4",
"bundler": "workspace:*",
"concurrently": "latest",
"config": "workspace:*",
"react-native-test-app": "^4.0.7",
"react-test-renderer": "^18.3.1",
"typescript": "^5.7.2",
"react-native-test-app": "^4.4.0",
"typescript": "^5.8.3",
"workbox-build": "^7.3.0",
"workbox-core": "^7.3.0",
"workbox-routing": "^7.3.0",
Expand Down
24 changes: 12 additions & 12 deletions client/src/app/data/lib/hfs-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import {FS} from 'react-exo/fs';
import {observe, poll} from 'media/dir/utils/hfs/fs';
import {poll} from 'media/dir/utils/hfs/fs';
import {useContext, useEffect, useState, createContext} from 'react';

import type {HfsImpl, HfsType} from 'react-exo/fs';
import type {HfsImpl} from 'react-exo/fs';

const HfsContext = createContext<HfsContextType | null>(null);
const $ = new Map<string, {callbacks: Set<WatchFn>, disconnect: () => void}>();

export type WatchFn = () => void;

export interface HfsProviderProps {
type?: HfsType;
}

export interface HfsContextType {
fs: HfsImpl | null;
watch: (path: string, fn: WatchFn) => () => void;
Expand All @@ -30,11 +26,11 @@ export function useHfsWatch(path: string, fn: WatchFn) {
useEffect(() => ctx.watch(path, fn), [path, fn, ctx]);
}

export function HfsProvider({type, children}: React.PropsWithChildren<HfsProviderProps>) {
export function HfsProvider({children}: React.PropsWithChildren) {
const [fs, setFs] = useState<HfsImpl | null>(null);

const register = async (path: string) => {
const disconnect = await observe(path, () => {
const disconnect = await FS.watch(path, () => {
const callbacks = $.get(path)?.callbacks;
if (!callbacks) return;
for (const c of callbacks) c();
Expand Down Expand Up @@ -71,15 +67,19 @@ export function HfsProvider({type, children}: React.PropsWithChildren<HfsProvide
if (!callbacks) return;
callbacks.delete(fn);
if (callbacks.size === 0) {
$.get(path)?.disconnect();
try {
$.get(path)?.disconnect();
} catch (e) {}
$.delete(path);
}
};
};

useEffect(() => {(async () =>
setFs(await FS.init(type)))();
}, [type]);
useEffect(() => {
(async () => {
setFs(await FS.init('local'));
})();
}, []);

return (
<HfsContext.Provider value={{fs, watch}}>
Expand Down
3 changes: 1 addition & 2 deletions client/src/app/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ export function Router() {
<Route path="storage" element={<$><Screen.Storage/></$>}/>
<Route path="settings" element={<Screen.Settings/>}/>
{/* Media */}
<Route path="browse/*" element={<$><Screen.Browse/></$>}/>
<Route path="ipfs/*" element={<$><Screen.Ipfs/></$>}/>
<Route path="browse/:backend/*" element={<$><Screen.Browse/></$>}/>
<Route path="ipfs/:cid/:filename" element={<$><Screen.Ipfs/></$>}/>
{/* World */}
<Route path="world" element={<$><Screen.World/></$>}/>
Expand Down
4 changes: 3 additions & 1 deletion client/src/app/routes/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export default function Layout() {
const focused = useGet(media.selectors.getFocused);
const isVert = screen.width < theme.breakpoints.sm;
const hasTabs = screen.width < theme.breakpoints.xs;
const hasPanel = (pathname.includes('/browse') && !isVert) || Boolean(focused);
const hasPanel = (!isVert && pathname.includes('/browse'))
|| (Boolean(focused) && !pathname.includes('/settings'));
const vstyles = {
root: [styles.root, hasTabs && styles.rootTabs],
menu: [styles.menu, hasTabs && styles.menuTabs],
Expand Down Expand Up @@ -69,6 +70,7 @@ export default function Layout() {
<Media
{...toPath(focused || pathname, false)}
vertical={isVert}
standalone={false}
maximized={true}
embedded={false}
close={() => {}}
Expand Down
Loading