`'s child `` component
* Renamed `'a'` variant to `'link'`
* Updated Solito fork to fix a mistake in Solito's typing
---
.env.example | 10 +
.gitignore | 4 +
docker-compose-setup/.env.example | 41 +++-
docker-compose-setup/docker-compose.yaml | 1 +
package.json | 5 +-
patches/@react-native__assets-registry.patch | 101 ++++++++
patches/next-sitemap.patch | 16 ++
pnpm-lock.yaml | 54 ++++-
scripts/build-nextjs-site.ps1 | 3 +
src/forks/assets-registry/package.json | 11 -
src/forks/assets-registry/path-support.js | 90 -------
src/forks/assets-registry/registry.js | 25 --
src/forks/solito | 2 +-
src/interface/components/FontAwesomeIcon.tsx | 43 ----
.../components/icons/dripsy-icons.tsx | 225 ++++++++++++++++++
.../features/getting-started-screen.tsx | 3 +-
src/interface/features/home-screen.tsx | 15 +-
src/interface/features/login-dialog.tsx | 22 +-
src/interface/features/unsupported-screen.tsx | 2 +-
src/interface/hooks/useCookies.web.ts | 3 +-
src/interface/package.json | 1 +
.../provider/auth/authentication.tsx | 2 +-
src/interface/provider/tRPC-provider.tsx | 2 +-
src/interface/provider/theme.tsx | 2 +-
src/lib/env-schema.ts | 24 ++
src/lib/env-utils.d.ts | 17 ++
src/lib/env-utils.js | 58 +++++
src/platforms/expo/app.config.ts | 2 +
src/platforms/expo/app/web/_layout.tsx | 6 +-
src/platforms/expo/metro.config.js | 15 +-
src/platforms/next/app/robots.ts | 17 ++
.../next/app/web/login/LoginPage.tsx | 3 +-
src/platforms/next/instrumentation.ts | 101 +++++++-
src/platforms/next/next.config.ts | 6 +
src/platforms/next/package.json | 2 +-
35 files changed, 714 insertions(+), 220 deletions(-)
create mode 100644 patches/@react-native__assets-registry.patch
create mode 100644 patches/next-sitemap.patch
delete mode 100644 src/forks/assets-registry/package.json
delete mode 100644 src/forks/assets-registry/path-support.js
delete mode 100644 src/forks/assets-registry/registry.js
delete mode 100644 src/interface/components/FontAwesomeIcon.tsx
create mode 100644 src/interface/components/icons/dripsy-icons.tsx
create mode 100644 src/lib/env-utils.d.ts
create mode 100644 src/lib/env-utils.js
create mode 100644 src/platforms/next/app/robots.ts
diff --git a/.env.example b/.env.example
index 3d3698c..280780f 100644
--- a/.env.example
+++ b/.env.example
@@ -10,6 +10,16 @@ IS_SAAS = false
EXPO_PUBLIC_DEFAULT_SERVER = 'https://10.0.0.128/'
NEXT_PUBLIC_BASEURL = 'https://10.0.0.128/'
+# OPTIONAL: Prefix for the asset URLs. May be a path or a full URL.
+#
+# Assets include fonts, images, Next.js scripts, static pages,
+# and other things that only change when the site/app is rebuilt.
+#
+# Examples:
+# - "/assets/"
+# - "https://cdn.example.com/"
+NEXT_PUBLIC_ASSET_PREFIX = 'https://10.0.0.128/'
+
SITE_PORT=3000
SUPABASE_STUDIO_PORT=4080
diff --git a/.gitignore b/.gitignore
index 37c0879..5046d73 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,10 @@ src/interface/components/icons/material-symbols/.commit-sha
docker-compose-setup/supabase_volumes/db/init/*
!docker-compose-setup/supabase_volumes/db/init/data.sql
+/src/platforms/next/public/robots.txt
+/src/platforms/next/public/sitemap*.xml
+
+
# Test Caching! (caching resources used in tests, not caching test results)
tests/cache
diff --git a/docker-compose-setup/.env.example b/docker-compose-setup/.env.example
index f7ffd7b..7a9b87d 100644
--- a/docker-compose-setup/.env.example
+++ b/docker-compose-setup/.env.example
@@ -90,6 +90,39 @@ DOCKER_SOCKET_LOCATION=/run/user/1000/docker.sock
+
+# OPTIONAL: Base URL of your web server, used for SEO metadata and the Web App Manifest.
+#
+# For an example, the default is "https://stockedhome.app/"
+NEXT_PUBLIC_BASEURL=
+
+
+
+# OPTIONAL: Prefix for the asset URLs. May be a path or a full URL.
+#
+# Assets include fonts, images, Next.js scripts, static pages,
+# and other things that only change when the site/app is rebuilt.
+#
+# Examples:
+# - "/assets/"
+# - "https://cdn.example.com/"
+NEXT_PUBLIC_ASSET_PREFIX=
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
############
# Database - You can change these to any PostgreSQL database that has logical replication enabled.
############
@@ -140,11 +173,3 @@ SUPABASE_PUBLIC_URL=http://localhost:${SUPABASE_STUDIO_PORT}
# Google Cloud Project details. Uncomment both in here and in Docker Compose to use.
#GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID
#GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER
-
-
-
-
-# OPTIONAL: Base URL of your web server, used for SEO metadata and the Web App Manifest.
-#
-# For an example, the default is "https://stockedhome.app/"
-NEXT_PUBLIC_BASEURL = ''
diff --git a/docker-compose-setup/docker-compose.yaml b/docker-compose-setup/docker-compose.yaml
index c16d519..4b65459 100644
--- a/docker-compose-setup/docker-compose.yaml
+++ b/docker-compose-setup/docker-compose.yaml
@@ -38,6 +38,7 @@ services:
USE_SAAS_UX: ${USE_SAAS_UX}
NODE_ENV: production
NEXT_PUBLIC_BASEURL: ${NEXT_PUBLIC_BASEURL:-https://stockedhome.app}
+ NEXT_PUBLIC_ASSET_PREFIX: ${NEXT_PUBLIC_ASSET_PREFIX:-}
studio:
diff --git a/package.json b/package.json
index 4ee694a..9d64de3 100644
--- a/package.json
+++ b/package.json
@@ -55,7 +55,6 @@
"@gorhom/bottom-sheet": "^4.6.4",
"@prisma/client": "^5.21.1",
"@react-native-cookies/cookies": "^6.2.1",
- "@react-native/assets-registry": "file:./src/forks/assets-registry",
"@stockedhome/codegen": "link:codegen/results",
"@stockedhome/expo-app": "file:./src/platforms/expo",
"@stockedhome/next-app": "file:./src/platforms/next",
@@ -114,7 +113,9 @@
"pnpm": {
"patchedDependencies": {
"@hexagon/base64": "patches/@hexagon__base64.patch",
- "react-native-safe-area-context": "patches/react-native-safe-area-context.patch"
+ "react-native-safe-area-context": "patches/react-native-safe-area-context.patch",
+ "@react-native/assets-registry": "patches/@react-native__assets-registry.patch",
+ "next-sitemap": "patches/next-sitemap.patch"
},
"overrides": {
"next": "^15.0.1",
diff --git a/patches/@react-native__assets-registry.patch b/patches/@react-native__assets-registry.patch
new file mode 100644
index 0000000..82655ae
--- /dev/null
+++ b/patches/@react-native__assets-registry.patch
@@ -0,0 +1,101 @@
+diff --git a/path-support.js b/path-support.js
+index f0a85af33ff98d3d6d8a9c279378eb2676af160a..87f5df3ccd7e2358ac83b8c6005f8ded60d28bf8 100755
+--- a/path-support.js
++++ b/path-support.js
+@@ -10,7 +10,7 @@
+
+ 'use strict';
+
+-import type {PackagerAsset} from './registry.js';
++//import type {PackagerAsset} from './registry.js';
+
+ const androidScaleSuffix = {
+ '0.75': 'ldpi',
+@@ -27,7 +27,7 @@ const ANDROID_BASE_DENSITY = 160;
+ * FIXME: using number to represent discrete scale numbers is fragile in essence because of
+ * floating point numbers imprecision.
+ */
+-function getAndroidAssetSuffix(scale: number): string {
++function getAndroidAssetSuffix(scale) {
+ if (scale.toString() in androidScaleSuffix) {
+ return androidScaleSuffix[scale.toString()];
+ }
+@@ -52,9 +52,9 @@ const drawableFileTypes = new Set([
+ ]);
+
+ function getAndroidResourceFolderName(
+- asset: PackagerAsset,
+- scale: number,
+-): string | $TEMPORARY$string<'raw'> {
++ asset,//: PackagerAsset,
++ scale,//: number,
++) {
+ if (!drawableFileTypes.has(asset.type)) {
+ return 'raw';
+ }
+@@ -72,7 +72,7 @@ function getAndroidResourceFolderName(
+ return 'drawable-' + suffix;
+ }
+
+-function getAndroidResourceIdentifier(asset: PackagerAsset): string {
++function getAndroidResourceIdentifier(asset) {
+ return (getBasePath(asset) + '/' + asset.name)
+ .toLowerCase()
+ .replace(/\//g, '_') // Encode folder structure in file name
+@@ -80,7 +80,7 @@ function getAndroidResourceIdentifier(asset: PackagerAsset): string {
+ .replace(/^assets_/, ''); // Remove "assets_" prefix
+ }
+
+-function getBasePath(asset: PackagerAsset): string {
++function getBasePath(asset) {
+ const basePath = asset.httpServerLocation;
+ return basePath.startsWith('/') ? basePath.slice(1) : basePath;
+ }
+diff --git a/registry.js b/registry.js
+index 02470da3c4962ad1bbdc62d9ed295c19ca4905fe..584c758f2d18f3dd611bcf2614528240346c8747 100755
+--- a/registry.js
++++ b/registry.js
+@@ -10,28 +10,28 @@
+
+ 'use strict';
+
+-export type PackagerAsset = {
+- +__packager_asset: boolean,
+- +fileSystemLocation: string,
+- +httpServerLocation: string,
+- +width: ?number,
+- +height: ?number,
+- +scales: Array,
+- +hash: string,
+- +name: string,
+- +type: string,
+- ...
+-};
++//export type PackagerAsset = {
++// +__packager_asset: boolean,
++// +fileSystemLocation: string,
++// +httpServerLocation: string,
++// +width: ?number,
++// +height: ?number,
++// +scales: Array,
++// +hash: string,
++// +name: string,
++// +type: string,
++// ...
++//};
+
+-const assets: Array = [];
++const assets = [];
+
+-function registerAsset(asset: PackagerAsset): number {
++function registerAsset(asset) {
+ // `push` returns new array length, so the first asset will
+ // get id 1 (not 0) to make the value truthy
+ return assets.push(asset);
+ }
+
+-function getAssetByID(assetId: number): PackagerAsset {
++function getAssetByID(assetId) {
+ return assets[assetId - 1];
+ }
+
diff --git a/patches/next-sitemap.patch b/patches/next-sitemap.patch
new file mode 100644
index 0000000..48289b0
--- /dev/null
+++ b/patches/next-sitemap.patch
@@ -0,0 +1,16 @@
+diff --git a/package.json b/package.json
+index 64d04d7664700d58e7914e8a01ee2a19227fd303..c22ec3aa572b2a36bea0b678679e72414842c60d 100644
+--- a/package.json
++++ b/package.json
+@@ -10,6 +10,11 @@
+ "import": "./dist/esm/index.js",
+ "require": "./dist/cjs/index.js",
+ "types": "./dist/@types/index.d.ts"
++ },
++ "./*": {
++ "import": "./dist/esm/*.js",
++ "require": "./dist/cjs/*.js",
++ "types": "./dist/@types/*.d.ts"
+ }
+ },
+ "files": [
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b61195c..3b126f1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -34,6 +34,12 @@ patchedDependencies:
'@hexagon/base64':
hash: bk3b67xqvbwrbmxnq32kp4kgs4
path: patches/@hexagon__base64.patch
+ '@react-native/assets-registry':
+ hash: pqbn5nxwvxzhe4b5dcl3zwyaam
+ path: patches/@react-native__assets-registry.patch
+ next-sitemap:
+ hash: ewhoppzled4v3me6np6nkrah5y
+ path: patches/next-sitemap.patch
react-native-safe-area-context:
hash: zbp4gquixe4lcc7ew6wgdqo7cy
path: patches/react-native-safe-area-context.patch
@@ -75,9 +81,6 @@ importers:
'@react-native-cookies/cookies':
specifier: ^6.2.1
version: 6.2.1(react-native@0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.2.79)(react@18.3.1))
- '@react-native/assets-registry':
- specifier: file:./src/forks/assets-registry
- version: link:src/forks/assets-registry
'@react-navigation/core':
specifier: '*'
version: 6.4.17(react@18.3.1)
@@ -265,8 +268,6 @@ importers:
codegen/results: {}
- src/forks/assets-registry: {}
-
src/forks/react-native-passkeys:
dependencies:
'@hexagon/base64':
@@ -327,6 +328,9 @@ importers:
'@hexagon/base64':
specifier: ^1.1.28
version: 1.1.28(patch_hash=bk3b67xqvbwrbmxnq32kp4kgs4)
+ '@stockehome/codegen':
+ specifier: link:../../codegen/results
+ version: link:../../codegen/results
dripsy:
specifier: ^4.3.5
version: 4.3.5
@@ -517,9 +521,6 @@ importers:
'@expo/next-adapter':
specifier: 6.0.0
version: 6.0.0(expo@51.0.36(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2)))(react-native-web@0.19.13(react-dom@18.2.0(react@18.3.1))(react@18.3.1))(webpack@5.95.0)
- '@react-native/assets-registry':
- specifier: link:../../forks/assets-registry
- version: link:../../forks/assets-registry
'@trpc/client':
specifier: 11.0.0-rc.413
version: 11.0.0-rc.413(@trpc/server@11.0.0-rc.413)
@@ -553,6 +554,9 @@ importers:
next-images:
specifier: ^1.8.5
version: 1.8.5(webpack@5.95.0)
+ next-sitemap:
+ specifier: ^4.2.3
+ version: 4.2.3(patch_hash=ewhoppzled4v3me6np6nkrah5y)(next@15.0.1(@babel/core@7.25.2)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)(sass@1.80.4))
raf:
specifier: ^3.4.1
version: 3.4.1
@@ -1527,6 +1531,9 @@ packages:
'@changesets/write@0.3.2':
resolution: {integrity: sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==}
+ '@corex/deepmerge@4.0.43':
+ resolution: {integrity: sha512-N8uEMrMPL0cu/bdboEWpQYb/0i2K5Qn8eCsxzOmxSggJbbQte7ljMRoXm917AbntqTGOzdTu+vP3KOOzoC70HQ==}
+
'@cspotcode/source-map-support@0.8.1':
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
@@ -2382,6 +2389,9 @@ packages:
'@motionone/utils@10.18.0':
resolution: {integrity: sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw==}
+ '@next/env@13.5.7':
+ resolution: {integrity: sha512-uVuRqoj28Ys/AI/5gVEgRAISd0KWI0HRjOO1CTpNgmX3ZsHb5mdn14Y59yk0IxizXdo7ZjsI2S7qbWnO+GNBcA==}
+
'@next/env@15.0.1':
resolution: {integrity: sha512-lc4HeDUKO9gxxlM5G2knTRifqhsY6yYpwuHspBZdboZe0Gp+rZHBNNSIjmQKDJIdRXiXGyVnSD6gafrbQPvILQ==}
@@ -6844,6 +6854,13 @@ packages:
peerDependencies:
webpack: ^4.0.0 || ^5.0.0
+ next-sitemap@4.2.3:
+ resolution: {integrity: sha512-vjdCxeDuWDzldhCnyFCQipw5bfpl4HmZA7uoo3GAaYGjGgfL4Cxb1CiztPuWGmS+auYs7/8OekRS8C2cjdAsjQ==}
+ engines: {node: '>=14.18'}
+ hasBin: true
+ peerDependencies:
+ next: ^15.0.1
+
next@15.0.1:
resolution: {integrity: sha512-PSkFkr/w7UnFWm+EP8y/QpHrJXMqpZzAXpergB/EqLPOh4SGPJXv1wj4mslr2hUZBAS9pX7/9YLIdxTv6fwytw==}
engines: {node: '>=18.18.0'}
@@ -11208,6 +11225,8 @@ snapshots:
human-id: 1.0.2
prettier: 2.8.8
+ '@corex/deepmerge@4.0.43': {}
+
'@cspotcode/source-map-support@0.8.1':
dependencies:
'@jridgewell/trace-mapping': 0.3.9
@@ -12408,6 +12427,8 @@ snapshots:
hey-listen: 1.0.8
tslib: 2.8.0
+ '@next/env@13.5.7': {}
+
'@next/env@15.0.1': {}
'@next/eslint-plugin-next@14.2.3':
@@ -13034,7 +13055,7 @@ snapshots:
invariant: 2.2.4
react-native: 0.74.5(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))(@types/react@18.2.79)(react@18.3.1)
- '@react-native/assets-registry@0.74.87': {}
+ '@react-native/assets-registry@0.74.87(patch_hash=pqbn5nxwvxzhe4b5dcl3zwyaam)': {}
'@react-native/babel-plugin-codegen@0.74.87(@babel/preset-env@7.24.7(@babel/core@7.25.2))':
dependencies:
@@ -13727,7 +13748,6 @@ snapshots:
'@stockedhome/next-app@file:src/platforms/next(kft327xdhmujbepfpv6ec4wrbm)':
dependencies:
'@expo/next-adapter': 6.0.0(expo@51.0.36(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2)))(react-native-web@0.19.13(react-dom@18.2.0(react@18.3.1))(react@18.3.1))(webpack@5.95.0)
- '@react-native/assets-registry': link:../../forks/assets-registry
'@trpc/client': 11.0.0-rc.413(@trpc/server@11.0.0-rc.413)
'@trpc/next': 11.0.0-rc.413(@tanstack/react-query@5.59.15(react@18.3.1))(@trpc/client@11.0.0-rc.413(@trpc/server@11.0.0-rc.413))(@trpc/react-query@11.0.0-rc.413(@tanstack/react-query@5.59.15(react@18.3.1))(@trpc/client@11.0.0-rc.413(@trpc/server@11.0.0-rc.413))(@trpc/server@11.0.0-rc.413)(react-dom@18.2.0(react@18.3.1))(react@18.3.1))(@trpc/server@11.0.0-rc.413)(next@15.0.1(@babel/core@7.25.2)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)(sass@1.80.4))(react-dom@18.2.0(react@18.3.1))(react@18.3.1)
'@trpc/react-query': 11.0.0-rc.413(@tanstack/react-query@5.59.15(react@18.3.1))(@trpc/client@11.0.0-rc.413(@trpc/server@11.0.0-rc.413))(@trpc/server@11.0.0-rc.413)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)
@@ -13739,6 +13759,7 @@ snapshots:
next-compose-plugins: 2.2.1
next-fonts: 1.5.1(webpack@5.95.0)
next-images: 1.8.5(webpack@5.95.0)
+ next-sitemap: 4.2.3(patch_hash=ewhoppzled4v3me6np6nkrah5y)(next@15.0.1(@babel/core@7.25.2)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)(sass@1.80.4))
raf: 3.4.1
sass: 1.80.4
setimmediate: 1.0.5
@@ -14548,6 +14569,7 @@ snapshots:
'@expo-google-fonts/rubik': 0.2.3
'@expo/html-elements': 0.10.1
'@hexagon/base64': 1.1.28(patch_hash=bk3b67xqvbwrbmxnq32kp4kgs4)
+ '@stockehome/codegen': link:../../codegen/results
dripsy: 4.3.5
expo-font: 12.0.10(expo@51.0.36(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2)))
expo-splash-screen: 0.27.6(expo-modules-autolinking@1.11.3)(expo@51.0.36(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2)))
@@ -18946,6 +18968,14 @@ snapshots:
url-loader: 4.1.1(file-loader@6.2.0(webpack@5.95.0))(webpack@5.95.0)
webpack: 5.95.0
+ next-sitemap@4.2.3(patch_hash=ewhoppzled4v3me6np6nkrah5y)(next@15.0.1(@babel/core@7.25.2)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)(sass@1.80.4)):
+ dependencies:
+ '@corex/deepmerge': 4.0.43
+ '@next/env': 13.5.7
+ fast-glob: 3.3.2
+ minimist: 1.2.8
+ next: 15.0.1(@babel/core@7.25.2)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)(sass@1.80.4)
+
next@15.0.1(@babel/core@7.25.2)(react-dom@18.2.0(react@18.3.1))(react@18.3.1)(sass@1.80.4):
dependencies:
'@next/env': 15.0.1
@@ -19677,7 +19707,7 @@ snapshots:
'@react-native-community/cli': 13.6.9
'@react-native-community/cli-platform-android': 13.6.9
'@react-native-community/cli-platform-ios': 13.6.9
- '@react-native/assets-registry': 0.74.87
+ '@react-native/assets-registry': 0.74.87(patch_hash=pqbn5nxwvxzhe4b5dcl3zwyaam)
'@react-native/codegen': 0.74.87(@babel/preset-env@7.25.4(@babel/core@7.24.7))
'@react-native/community-cli-plugin': 0.74.87(@babel/core@7.24.7)(@babel/preset-env@7.25.4(@babel/core@7.24.7))
'@react-native/gradle-plugin': 0.74.87
@@ -19727,7 +19757,7 @@ snapshots:
'@react-native-community/cli': 13.6.9
'@react-native-community/cli-platform-android': 13.6.9
'@react-native-community/cli-platform-ios': 13.6.9
- '@react-native/assets-registry': 0.74.87
+ '@react-native/assets-registry': 0.74.87(patch_hash=pqbn5nxwvxzhe4b5dcl3zwyaam)
'@react-native/codegen': 0.74.87(@babel/preset-env@7.25.4(@babel/core@7.25.2))
'@react-native/community-cli-plugin': 0.74.87(@babel/core@7.25.2)(@babel/preset-env@7.25.4(@babel/core@7.25.2))
'@react-native/gradle-plugin': 0.74.87
diff --git a/scripts/build-nextjs-site.ps1 b/scripts/build-nextjs-site.ps1
index a8f9496..97f8ad6 100644
--- a/scripts/build-nextjs-site.ps1
+++ b/scripts/build-nextjs-site.ps1
@@ -1,6 +1,9 @@
$ErrorActionPreference = "Stop"
Set-Location $PSScriptRoot/..
+Write-Host "Building Next.js site" -ForegroundColor DarkCyan
+Write-Host ""
+
pnpm exec next build src/platforms/next
if ($?) {
Write-Host "Next.js build successful" -ForegroundColor Green
diff --git a/src/forks/assets-registry/package.json b/src/forks/assets-registry/package.json
deleted file mode 100644
index ea0d35f..0000000
--- a/src/forks/assets-registry/package.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name": "@react-native/assets-registry",
- "version": "0.72.0",
- "description": "Asset support code for React Native.",
- "repository": {
- "type": "git",
- "url": "git@github.com:facebook/react-native.git",
- "directory": "packages/assets"
- },
- "license": "MIT"
-}
diff --git a/src/forks/assets-registry/path-support.js b/src/forks/assets-registry/path-support.js
deleted file mode 100644
index 911a1d4..0000000
--- a/src/forks/assets-registry/path-support.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict
- */
-
-'use strict';
-
-const androidScaleSuffix = {
- '0.75': 'ldpi',
- '1': 'mdpi',
- '1.5': 'hdpi',
- '2': 'xhdpi',
- '3': 'xxhdpi',
- '4': 'xxxhdpi',
-};
-
-const ANDROID_BASE_DENSITY = 160;
-
-/**
- * FIXME: using number to represent discrete scale numbers is fragile in essence because of
- * floating point numbers imprecision.
- */
-function getAndroidAssetSuffix(scale) {
- if (scale.toString() in androidScaleSuffix) {
- return androidScaleSuffix[scale.toString()];
- }
- // NOTE: Android Gradle Plugin does not fully support the nnndpi format.
- // See https://issuetracker.google.com/issues/72884435
- if (Number.isFinite(scale) && scale > 0) {
- return Math.round(scale * ANDROID_BASE_DENSITY) + 'dpi';
- }
- throw new Error('no such scale ' + scale.toString());
-}
-
-// See https://developer.android.com/guide/topics/resources/drawable-resource.html
-const drawableFileTypes = new Set([
- 'gif',
- 'jpeg',
- 'jpg',
- 'ktx',
- 'png',
- 'svg',
- 'webp',
- 'xml',
-]);
-
-function getAndroidResourceFolderName(
- asset,
- scale,
-) {
- if (!drawableFileTypes.has(asset.type)) {
- return 'raw';
- }
- const suffix = getAndroidAssetSuffix(scale);
- if (!suffix) {
- throw new Error(
- "Don't know which android drawable suffix to use for scale: " +
- scale +
- '\nAsset: ' +
- JSON.stringify(asset, null, '\t') +
- '\nPossible scales are:' +
- JSON.stringify(androidScaleSuffix, null, '\t'),
- );
- }
- return 'drawable-' + suffix;
-}
-
-function getAndroidResourceIdentifier(asset) {
- return (getBasePath(asset) + '/' + asset.name)
- .toLowerCase()
- .replace(/\//g, '_') // Encode folder structure in file name
- .replace(/([^a-z0-9_])/g, '') // Remove illegal chars
- .replace(/^assets_/, ''); // Remove "assets_" prefix
-}
-
-function getBasePath(asset) {
- const basePath = asset.httpServerLocation;
- return basePath.startsWith('/') ? basePath.slice(1) : basePath;
-}
-
-module.exports = {
- getAndroidResourceFolderName,
- getAndroidResourceIdentifier,
- getBasePath,
-};
diff --git a/src/forks/assets-registry/registry.js b/src/forks/assets-registry/registry.js
deleted file mode 100644
index 3851d92..0000000
--- a/src/forks/assets-registry/registry.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow strict
- * @format
- */
-
-'use strict';
-
-const assets = [];
-
-function registerAsset(asset) {
- // `push` returns new array length, so the first asset will
- // get id 1 (not 0) to make the value truthy
- return assets.push(asset);
-}
-
-function getAssetByID(assetId) {
- return assets[assetId - 1];
-}
-
-module.exports = {registerAsset, getAssetByID};
diff --git a/src/forks/solito b/src/forks/solito
index 71cab3d..205e4e7 160000
--- a/src/forks/solito
+++ b/src/forks/solito
@@ -1 +1 @@
-Subproject commit 71cab3d370a6377d6e09571363df2836d104479f
+Subproject commit 205e4e731f6fa6138785db919d1bb45870459c25
diff --git a/src/interface/components/FontAwesomeIcon.tsx b/src/interface/components/FontAwesomeIcon.tsx
deleted file mode 100644
index 66a2f9f..0000000
--- a/src/interface/components/FontAwesomeIcon.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-'use client';
-
-import React, { ComponentProps } from 'react';
-import { createThemedComponent, useDripsyTheme, ColorPath, StyledProps } from 'dripsy';
-import { get } from 'dripsy/build/core/css/get';
-import { FontAwesomeIcon as RFontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
-
-const DripsyFontAwesomeIcon = createThemedComponent(RFontAwesomeIcon, {
- themeKey: 'images',
- defaultVariant: 'icon',
-});
-
-type InputProps = React.ComponentPropsWithoutRef;
-type ColorKeys = keyof Pick<
- InputProps,
- 'color' | 'secondaryColor'
->;
-
-export type DripsyTextInputProps = StyledProps<'missing'> &
- Omit, ColorKeys> &
- {
- [key in ColorKeys]?: (string & {}) | ColorPath
- };
-
-const colorKeys: Record = {
- color: true,
- secondaryColor: true,
-};
-
-export function FontAwesomeIcon({ ...props }: Parameters[0]) {
- const { theme } = useDripsyTheme();
-
- const propsToPass = React.useMemo(() => {
- const generatedProps = { ...props };
- Object.keys(colorKeys).forEach((key: ColorKeys) => {
- if (props[key] && theme?.colors)
- generatedProps[key] = get(theme.colors, props[key] as string) ?? props[key];
- });
- return generatedProps;
- }, [theme, props]);
-
- return ;
-};
diff --git a/src/interface/components/icons/dripsy-icons.tsx b/src/interface/components/icons/dripsy-icons.tsx
new file mode 100644
index 0000000..3519b35
--- /dev/null
+++ b/src/interface/components/icons/dripsy-icons.tsx
@@ -0,0 +1,225 @@
+'use client';
+
+import React from 'react';
+import { createThemedComponent, useDripsyTheme, ColorPath, StyledProps } from 'dripsy';
+import { get } from 'dripsy/build/core/css/get';
+import { FontAwesomeIcon as FontAwesome } from '@fortawesome/react-native-fontawesome';
+import MaterialSymbols from './MaterialSymbols';
+import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
+import Octicons from '@expo/vector-icons/Octicons';
+import FontAwesome5 from '@expo/vector-icons/FontAwesome5';
+import FontAwesome6 from '@expo/vector-icons/FontAwesome6';
+
+// Really, Expo? Major typing blunder right---multi-font icons are declared as `any`.
+// Might as well fix it here since I have an opportunity.
+import type { IconProps } from '@expo/vector-icons/build/createIconSet';
+import type FA5GlyphMap from '@expo/vector-icons/build/vendor/react-native-vector-icons/glyphmaps/FontAwesome5Free.json';
+import type FA6GlyphMap from '@expo/vector-icons/build/vendor/react-native-vector-icons/glyphmaps/FontAwesome6Free.json';
+
+const DripsyFontAwesomeIcon = createThemedComponent(FontAwesome, {
+ themeKey: 'images',
+ defaultVariant: 'icon',
+});
+
+type FAIconProps = React.ComponentPropsWithoutRef;
+type FAColorKeys = keyof Pick<
+ FAIconProps,
+ 'color' | 'secondaryColor'
+>;
+
+export type DripsyFontAwesomeIconProps = StyledProps<'images'> &
+ Omit &
+ {
+ [key in FAColorKeys]?: (string & {}) | ColorPath
+ };
+
+const faColorKeys: Record = {
+ color: true,
+ secondaryColor: true,
+};
+
+export function FontAwesomeIcon({ ...props }: DripsyFontAwesomeIconProps) {
+ const { theme } = useDripsyTheme();
+
+ const propsToPass = React.useMemo(() => {
+ const generatedProps = { ...props };
+ Object.keys(faColorKeys).forEach((key: FAColorKeys) => {
+ if (props[key] && theme?.colors)
+ generatedProps[key] = get(theme.colors, props[key] as string) ?? props[key];
+ });
+ return generatedProps;
+ }, [theme, props]);
+
+ return ;
+};
+
+const DripsyMaterialSymbolsIcon = createThemedComponent(MaterialSymbols, {
+ themeKey: 'images',
+ defaultVariant: 'icon',
+});
+
+export type MaterialSymbolsProps = React.ComponentPropsWithoutRef;
+type MaterialSymbolsColorKeys = keyof Pick<
+ MaterialSymbolsProps,
+ 'color'
+>;
+
+export type DripsyMaterialSymbolsIconProps = StyledProps<'images'> &
+ Omit &
+ {
+ [key in MaterialSymbolsColorKeys]?: (string & {}) | ColorPath
+ };
+
+const materialSymbolsColorKeys: Record = {
+ color: true,
+};
+
+export function MaterialSymbolsIcon({ ...props }: DripsyMaterialSymbolsIconProps) {
+ const { theme } = useDripsyTheme();
+
+ const propsToPass = React.useMemo(() => {
+ const generatedProps = { ...props };
+ Object.keys(materialSymbolsColorKeys).forEach((key: MaterialSymbolsColorKeys) => {
+ if (props[key] && theme?.colors)
+ generatedProps[key] = get(theme.colors, props[key] as string) ?? props[key];
+ });
+ return generatedProps;
+ }, [theme, props]);
+
+ return ;
+};
+
+const DripsyMaterialCommunityIcon = createThemedComponent(MaterialCommunityIcons, {
+ themeKey: 'images',
+ defaultVariant: 'icon',
+});
+
+export type MaterialCommunityIconProps = React.ComponentPropsWithoutRef;
+type MaterialCommunityIconColorKeys = keyof Pick<
+ MaterialCommunityIconProps,
+ 'color'
+>;
+
+export type DripsyMaterialCommunityIconProps = StyledProps<'images'> &
+ Omit &
+ {
+ [key in MaterialCommunityIconColorKeys]?: (string & {}) | ColorPath
+ };
+
+const materialCommunityIconColorKeys: Record = {
+ color: true,
+};
+
+export function MaterialCommunityIcon({ ...props }: DripsyMaterialCommunityIconProps) {
+ const { theme } = useDripsyTheme();
+
+ const propsToPass = React.useMemo(() => {
+ const generatedProps = { ...props };
+ Object.keys(materialCommunityIconColorKeys).forEach((key: MaterialCommunityIconColorKeys) => {
+ if (props[key] && theme?.colors)
+ generatedProps[key] = get(theme.colors, props[key] as string) ?? props[key];
+ });
+ return generatedProps;
+ }, [theme, props]);
+
+ return ;
+};
+
+const DripsyOcticonsIcon = createThemedComponent(Octicons, {
+ themeKey: 'images',
+ defaultVariant: 'icon',
+});
+
+export type OcticonsIconProps = React.ComponentPropsWithoutRef;
+
+export type DripsyOcticonsIconProps = StyledProps<'images'> &
+ Omit &
+ {
+ color?: (string & {}) | ColorPath
+ };
+
+export function OcticonsIcon({ ...props }: DripsyOcticonsIconProps) {
+ const { theme } = useDripsyTheme();
+
+ const propsToPass = React.useMemo(() => {
+ const generatedProps = { ...props };
+ if (props.color && theme?.colors)
+ generatedProps.color = get(theme.colors, props.color as string) ?? props.color;
+ return generatedProps;
+ }, [theme, props]);
+
+ return ;
+}
+
+const DripsyFontAwesome5Icon = createThemedComponent(FontAwesome5, {
+ themeKey: 'images',
+ defaultVariant: 'icon',
+});
+
+export type FontAwesome5IconProps = IconProps;
+type FontAwesome5IconColorKeys = keyof Pick<
+ FontAwesome5IconProps,
+ 'color'
+>;
+
+export type DripsyFontAwesome5IconProps = StyledProps<'images'> &
+ Omit &
+ {
+ [key in FontAwesome5IconColorKeys]?: (string & {}) | ColorPath
+ };
+
+const fontAwesome5IconColorKeys: Record = {
+ color: true,
+};
+
+export function FontAwesome5Icon({ ...props }: DripsyFontAwesome5IconProps) {
+ const { theme } = useDripsyTheme();
+
+ const propsToPass = React.useMemo(() => {
+ const generatedProps = { ...props };
+ Object.keys(fontAwesome5IconColorKeys).forEach((key: FontAwesome5IconColorKeys) => {
+ if (props[key] && theme?.colors)
+ generatedProps[key] = get(theme.colors, props[key] as string) ?? props[key];
+ });
+ return generatedProps;
+ }, [theme, props]);
+
+ return ;
+};
+
+const DripsyFontAwesome6Icon = createThemedComponent(FontAwesome6, {
+ themeKey: 'images',
+ defaultVariant: 'icon',
+});
+
+
+export type FontAwesome6IconProps = IconProps;
+type FontAwesome6IconColorKeys = keyof Pick<
+ FontAwesome6IconProps,
+ 'color'
+>;
+
+export type DripsyFontAwesome6IconProps = StyledProps<'images'> &
+ Omit &
+ {
+ [key in FontAwesome6IconColorKeys]?: (string & {}) | ColorPath
+ };
+
+const fontAwesome6IconColorKeys: Record = {
+ color: true,
+};
+
+export function FontAwesome6Icon({ ...props }: DripsyFontAwesome6IconProps) {
+ const { theme } = useDripsyTheme();
+
+ const propsToPass = React.useMemo(() => {
+ const generatedProps = { ...props };
+ Object.keys(fontAwesome6IconColorKeys).forEach((key: FontAwesome6IconColorKeys) => {
+ if (props[key] && theme?.colors)
+ generatedProps[key] = get(theme.colors, props[key] as string) ?? props[key];
+ });
+ return generatedProps;
+ }, [theme, props]);
+
+ return ;
+};
diff --git a/src/interface/features/getting-started-screen.tsx b/src/interface/features/getting-started-screen.tsx
index 132bc44..324bc7e 100644
--- a/src/interface/features/getting-started-screen.tsx
+++ b/src/interface/features/getting-started-screen.tsx
@@ -5,6 +5,7 @@ import { TextLink } from 'solito/link';
import { Image } from '../components/image/Image';
import { OptionallyScrollable } from '../components/TopLevelScreenView';
import { useAuthentication } from '../provider/auth/authentication';
+import { getPublicEnvValue } from 'lib/env-utils';
export function GettingStartedScreen() {
return
@@ -80,7 +81,7 @@ function GettingStartedScreenInternal() {