├── native ├── android │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── values-night │ │ │ │ │ │ └── colors.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ ├── ic_launcher.webp │ │ │ │ │ │ └── ic_launcher_foreground.webp │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ ├── ic_launcher.webp │ │ │ │ │ │ └── ic_launcher_foreground.webp │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ ├── ic_launcher.webp │ │ │ │ │ │ └── ic_launcher_foreground.webp │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ ├── ic_launcher.webp │ │ │ │ │ │ └── ic_launcher_foreground.webp │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ ├── ic_launcher.webp │ │ │ │ │ │ └── ic_launcher_foreground.webp │ │ │ │ │ ├── drawable-hdpi │ │ │ │ │ │ └── splashscreen_logo.png │ │ │ │ │ ├── drawable-mdpi │ │ │ │ │ │ └── splashscreen_logo.png │ │ │ │ │ ├── drawable-xhdpi │ │ │ │ │ │ └── splashscreen_logo.png │ │ │ │ │ ├── drawable-xxhdpi │ │ │ │ │ │ └── splashscreen_logo.png │ │ │ │ │ ├── drawable-xxxhdpi │ │ │ │ │ │ └── splashscreen_logo.png │ │ │ │ │ ├── drawable │ │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ │ └── values │ │ │ │ │ │ ├── colors.xml │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ └── styles.xml │ │ │ │ ├── java │ │ │ │ │ └── com │ │ │ │ │ │ └── guardianghost │ │ │ │ │ │ ├── MainApplication.kt │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── debugOptimized │ │ │ │ └── AndroidManifest.xml │ │ ├── debug.keystore │ │ └── proguard-rules.pro │ ├── WhatsNew │ │ └── whatsnew-en-US │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── sentry.properties │ ├── .gitignore │ ├── build.gradle │ └── settings.gradle ├── nativewind-env.d.ts ├── .npmrc ├── ReleaseNotes │ └── whatsnew-en ├── public │ ├── logo192.png │ ├── logo512.png │ ├── .well-known │ │ ├── assetlinks.json │ │ └── apple-app-site-association │ └── manifest.json ├── images │ ├── crafted.webp │ ├── enhanced.webp │ ├── cross-save.png │ ├── damage │ │ ├── arc.png │ │ ├── solar.png │ │ ├── void.png │ │ ├── stasis.png │ │ ├── strand.png │ │ ├── arc_mini.webp │ │ ├── void_mini.webp │ │ ├── solar_mini.webp │ │ ├── stasis_mini.webp │ │ ├── strand_mini.webp │ │ └── kinetic_mini.webp │ ├── hunter-logo.png │ ├── icons │ │ ├── search.png │ │ ├── refresh.webp │ │ ├── power-icon.png │ │ ├── refresh@2x.webp │ │ ├── refresh@3x.webp │ │ ├── inventory-item-tier2.png │ │ ├── inventory-item-tier3.png │ │ ├── inventory-item-tier4.png │ │ └── inventory-item-tier5.png │ ├── titan-logo.png │ ├── vaultEmblem.webp │ ├── warlock-logo.png │ ├── engram-empty.webp │ ├── enhanced-trait.png │ ├── gg-logo-dark.webp │ ├── gg-logo-light.webp │ ├── globalEmblem.webp │ ├── large-crafted.webp │ ├── objectives │ │ ├── arc.png │ │ ├── bow.png │ │ ├── smg.png │ │ ├── fusion.png │ │ ├── glaive.png │ │ ├── melee.png │ │ ├── quest.png │ │ ├── solar.png │ │ ├── stasis.png │ │ ├── sword.png │ │ ├── void.png │ │ ├── currency.png │ │ ├── grenade.png │ │ ├── headshot.png │ │ ├── shotgun.png │ │ ├── sidearm.png │ │ ├── auto rifle.png │ │ ├── final blows.png │ │ ├── hand cannon.png │ │ ├── lost sector.png │ │ ├── machine gun.png │ │ ├── pulse rifle.png │ │ ├── scout rifle.png │ │ ├── trace rifle.png │ │ ├── large blocker.png │ │ ├── linear fusion.png │ │ ├── small blocker.png │ │ ├── sniper rifle.png │ │ ├── grenade launcher.png │ │ ├── medium blocker.png │ │ ├── rocket launcher.png │ │ └── special grenade launcher.png │ ├── gg-logo-dark@2x.webp │ ├── gg-logo-dark@3x.webp │ ├── gg-logo-light@2x.webp │ ├── gg-logo-light@3x.webp │ ├── large-enhanced.webp │ ├── vaultSecondary.webp │ ├── vault-emblem-button.png │ ├── details-masterwork-trim.png │ ├── masterwork-landscape-overlay.png │ ├── svg │ │ ├── twitch.svg │ │ ├── ellipses-horizontal.svg │ │ ├── psn.svg │ │ ├── steam.svg │ │ ├── xbox.svg │ │ └── epic.svg │ ├── shield.svg │ ├── sword.svg │ └── package.svg ├── assets │ └── images │ │ ├── icon.png │ │ ├── favicon.png │ │ ├── splash.png │ │ ├── splash_dark.png │ │ └── adaptive-icon.png ├── ios │ ├── GuardianGhost │ │ ├── Images.xcassets │ │ │ ├── Contents.json │ │ │ ├── SplashScreenLogo.imageset │ │ │ │ ├── image.png │ │ │ │ ├── image@2x.png │ │ │ │ ├── image@3x.png │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── App-Icon-1024x1024@1x.png │ │ │ │ └── Contents.json │ │ │ └── SplashScreenBackground.colorset │ │ │ │ └── Contents.json │ │ ├── GuardianGhost-Bridging-Header.h │ │ ├── GuardianGhost.entitlements │ │ ├── Supporting │ │ │ └── Expo.plist │ │ ├── PrivacyInfo.xcprivacy │ │ ├── AppDelegate.swift │ │ └── Info.plist │ ├── TestFlight │ │ └── WhatToTest.en-US.txt │ ├── sentry.properties │ ├── Podfile.properties.json │ ├── GuardianGhost.xcworkspace │ │ └── contents.xcworkspacedata │ ├── .gitignore │ ├── .xcode.env │ ├── ci_scripts │ │ └── ci_post_clone.sh │ └── Podfile ├── components.json ├── eslint.config.js ├── declaractions.d.ts ├── lib │ ├── icons │ │ ├── Check.tsx │ │ ├── Shield.tsx │ │ ├── Swords.tsx │ │ ├── ChevronUp.tsx │ │ ├── ChevronDown.tsx │ │ ├── Refresh-ccw.tsx │ │ ├── ChevronRight.tsx │ │ └── iconWithClassName.ts │ ├── utils.ts │ └── useColorScheme.tsx ├── .gitignore ├── metro.config.js ├── app │ ├── inventory │ │ ├── sections │ │ │ ├── VaultSpacerUI.tsx │ │ │ ├── ArtifactUI.tsx │ │ │ ├── LootItemRow.tsx │ │ │ ├── EngramsUI.tsx │ │ │ ├── CharacterEquipmentUI.tsx │ │ │ └── LostItemsUI.tsx │ │ ├── pages │ │ │ ├── ArmorPage.tsx │ │ │ ├── GeneralPage.tsx │ │ │ ├── WeaponsPage.tsx │ │ │ ├── ResultsSectionUI.tsx │ │ │ ├── details │ │ │ │ └── QuantityPicker.tsx │ │ │ ├── InventoryPages.tsx │ │ │ └── InventoryHeader.tsx │ │ ├── UiRowRenderItem.tsx │ │ └── cells │ │ │ ├── EmptyCell.tsx │ │ │ └── EngramCell.tsx │ ├── _authenticated │ │ ├── (drawer) │ │ │ ├── (tabs) │ │ │ │ ├── armor.tsx │ │ │ │ ├── weapons.tsx │ │ │ │ ├── inventory.tsx │ │ │ │ └── _layout.tsx │ │ │ ├── settings.tsx │ │ │ └── search.tsx │ │ ├── _layout.tsx │ │ └── details │ │ │ └── _layout.tsx │ ├── UI │ │ ├── Text.tsx │ │ └── Spinner.tsx │ ├── store │ │ ├── Types.ts │ │ ├── SettingsSlice.ts │ │ ├── UIDataSlice.ts │ │ └── GGStore.ts │ ├── index.js │ ├── stats │ │ ├── PerkCircle.tsx │ │ ├── Stats.tsx │ │ └── RecoilStat.tsx │ ├── App.tsx │ ├── bungie │ │ └── Account.ts │ ├── screens │ │ └── Settings.tsx │ ├── core │ │ └── generated │ │ │ └── HelperKeys.ts │ └── index.tsx ├── README.md ├── babel.config.js ├── eas.json ├── constants │ ├── Colors.ts │ └── env.ts ├── global.css ├── components │ └── ui │ │ ├── text.tsx │ │ ├── label.tsx │ │ └── radio-group.tsx ├── tsconfig.json ├── knip.config.ts ├── tailwind.config.js └── app.json ├── .npmrc ├── minifier ├── .gitignore ├── bun.lockb ├── package.json └── tsconfig.json ├── mono ├── apps │ └── site │ │ ├── tsconfig.json │ │ ├── public │ │ └── images │ │ │ ├── phone.webp │ │ │ ├── google-play-badge.png │ │ │ └── favicon.svg │ │ ├── astro.config.mjs │ │ ├── src │ │ ├── env.d.ts │ │ ├── pages │ │ │ └── index.astro │ │ └── styles │ │ │ └── main.css │ │ ├── package.json │ │ └── README.md ├── docs │ └── starlight │ │ ├── tsconfig.json │ │ ├── src │ │ ├── env.d.ts │ │ ├── assets │ │ │ ├── houston.webp │ │ │ ├── guardian-loot.webp │ │ │ └── transferSystem.webp │ │ └── content │ │ │ ├── docs │ │ │ ├── guides │ │ │ │ ├── architecture.mdx │ │ │ │ ├── costs.md │ │ │ │ ├── misc.md │ │ │ │ ├── todo.mdx │ │ │ │ ├── infrastructure.md │ │ │ │ ├── project-maintenance.mdx │ │ │ │ ├── authentication.md │ │ │ │ ├── react-native.md │ │ │ │ └── monorepo.mdx │ │ │ └── index.mdx │ │ │ └── config.ts │ │ ├── .vscode │ │ ├── extensions.json │ │ └── launch.json │ │ ├── vitest.config.ts │ │ ├── public │ │ └── favicon.svg │ │ ├── package.json │ │ ├── astro.config.mjs │ │ └── README.md └── examples │ └── default-project │ ├── src │ ├── assets │ │ └── favicon.ico │ ├── index.css │ ├── index.tsx │ ├── App.module.css │ ├── App.tsx │ └── logo.svg │ ├── README.md │ ├── tsconfig.json │ ├── vite.config.ts │ ├── index.html │ └── package.json ├── .vscode └── extensions.json ├── .github ├── ISSUE_TEMPLATE │ ├── app-issue.md │ ├── feature_request.md │ └── bug_report.md ├── workflows │ ├── main-mono.yml │ ├── deploy-gg-landing.yml │ ├── deploy-docs.yml │ ├── autofix.yaml │ ├── codeql.yml │ ├── update-definitions.yml │ └── deploy-gg-web.yml └── dependabot.yml ├── turbo.json ├── .watchmanconfig ├── pnpm-workspace.yaml ├── .gitignore ├── package.json ├── cSpell.json ├── README.md ├── LICENSE ├── patches └── @gorhom__bottom-sheet.patch └── biome.json /native/android/app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # New dependencies should be an exact version 2 | save-prefix="" -------------------------------------------------------------------------------- /minifier/.gitignore: -------------------------------------------------------------------------------- 1 | json/ 2 | benchmark-results.json 3 | baseline-output/ -------------------------------------------------------------------------------- /native/nativewind-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /native/.npmrc: -------------------------------------------------------------------------------- 1 | # New dependencies should be an exact version 2 | save-prefix="" -------------------------------------------------------------------------------- /native/ReleaseNotes/whatsnew-en: -------------------------------------------------------------------------------- 1 | 1.2.0 2 | 3 | Update all libraries.... 4 | -------------------------------------------------------------------------------- /mono/apps/site/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/base" 3 | } 4 | -------------------------------------------------------------------------------- /mono/docs/starlight/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strictest" 3 | } -------------------------------------------------------------------------------- /minifier/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/minifier/bun.lockb -------------------------------------------------------------------------------- /native/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/public/logo192.png -------------------------------------------------------------------------------- /native/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/public/logo512.png -------------------------------------------------------------------------------- /native/images/crafted.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/crafted.webp -------------------------------------------------------------------------------- /native/images/enhanced.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/enhanced.webp -------------------------------------------------------------------------------- /native/assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/assets/images/icon.png -------------------------------------------------------------------------------- /native/images/cross-save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/cross-save.png -------------------------------------------------------------------------------- /native/images/damage/arc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/damage/arc.png -------------------------------------------------------------------------------- /native/images/damage/solar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/damage/solar.png -------------------------------------------------------------------------------- /native/images/damage/void.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/damage/void.png -------------------------------------------------------------------------------- /native/images/hunter-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/hunter-logo.png -------------------------------------------------------------------------------- /native/images/icons/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/icons/search.png -------------------------------------------------------------------------------- /native/images/titan-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/titan-logo.png -------------------------------------------------------------------------------- /native/images/vaultEmblem.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/vaultEmblem.webp -------------------------------------------------------------------------------- /native/images/warlock-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/warlock-logo.png -------------------------------------------------------------------------------- /mono/docs/starlight/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /native/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/assets/images/favicon.png -------------------------------------------------------------------------------- /native/assets/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/assets/images/splash.png -------------------------------------------------------------------------------- /native/images/damage/stasis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/damage/stasis.png -------------------------------------------------------------------------------- /native/images/damage/strand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/damage/strand.png -------------------------------------------------------------------------------- /native/images/engram-empty.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/engram-empty.webp -------------------------------------------------------------------------------- /native/images/enhanced-trait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/enhanced-trait.png -------------------------------------------------------------------------------- /native/images/gg-logo-dark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/gg-logo-dark.webp -------------------------------------------------------------------------------- /native/images/gg-logo-light.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/gg-logo-light.webp -------------------------------------------------------------------------------- /native/images/globalEmblem.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/globalEmblem.webp -------------------------------------------------------------------------------- /native/images/icons/refresh.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/icons/refresh.webp -------------------------------------------------------------------------------- /native/images/large-crafted.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/large-crafted.webp -------------------------------------------------------------------------------- /native/images/objectives/arc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/arc.png -------------------------------------------------------------------------------- /native/images/objectives/bow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/bow.png -------------------------------------------------------------------------------- /native/images/objectives/smg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/smg.png -------------------------------------------------------------------------------- /native/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/debug.keystore -------------------------------------------------------------------------------- /native/images/damage/arc_mini.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/damage/arc_mini.webp -------------------------------------------------------------------------------- /native/images/damage/void_mini.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/damage/void_mini.webp -------------------------------------------------------------------------------- /native/images/gg-logo-dark@2x.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/gg-logo-dark@2x.webp -------------------------------------------------------------------------------- /native/images/gg-logo-dark@3x.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/gg-logo-dark@3x.webp -------------------------------------------------------------------------------- /native/images/gg-logo-light@2x.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/gg-logo-light@2x.webp -------------------------------------------------------------------------------- /native/images/gg-logo-light@3x.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/gg-logo-light@3x.webp -------------------------------------------------------------------------------- /native/images/icons/power-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/icons/power-icon.png -------------------------------------------------------------------------------- /native/images/icons/refresh@2x.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/icons/refresh@2x.webp -------------------------------------------------------------------------------- /native/images/icons/refresh@3x.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/icons/refresh@3x.webp -------------------------------------------------------------------------------- /native/images/large-enhanced.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/large-enhanced.webp -------------------------------------------------------------------------------- /native/images/objectives/fusion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/fusion.png -------------------------------------------------------------------------------- /native/images/objectives/glaive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/glaive.png -------------------------------------------------------------------------------- /native/images/objectives/melee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/melee.png -------------------------------------------------------------------------------- /native/images/objectives/quest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/quest.png -------------------------------------------------------------------------------- /native/images/objectives/solar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/solar.png -------------------------------------------------------------------------------- /native/images/objectives/stasis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/stasis.png -------------------------------------------------------------------------------- /native/images/objectives/sword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/sword.png -------------------------------------------------------------------------------- /native/images/objectives/void.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/void.png -------------------------------------------------------------------------------- /native/images/vaultSecondary.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/vaultSecondary.webp -------------------------------------------------------------------------------- /native/assets/images/splash_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/assets/images/splash_dark.png -------------------------------------------------------------------------------- /native/images/damage/solar_mini.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/damage/solar_mini.webp -------------------------------------------------------------------------------- /native/images/damage/stasis_mini.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/damage/stasis_mini.webp -------------------------------------------------------------------------------- /native/images/damage/strand_mini.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/damage/strand_mini.webp -------------------------------------------------------------------------------- /native/images/objectives/currency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/currency.png -------------------------------------------------------------------------------- /native/images/objectives/grenade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/grenade.png -------------------------------------------------------------------------------- /native/images/objectives/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/headshot.png -------------------------------------------------------------------------------- /native/images/objectives/shotgun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/shotgun.png -------------------------------------------------------------------------------- /native/images/objectives/sidearm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/sidearm.png -------------------------------------------------------------------------------- /native/images/vault-emblem-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/vault-emblem-button.png -------------------------------------------------------------------------------- /mono/apps/site/public/images/phone.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/mono/apps/site/public/images/phone.webp -------------------------------------------------------------------------------- /native/assets/images/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/assets/images/adaptive-icon.png -------------------------------------------------------------------------------- /native/images/damage/kinetic_mini.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/damage/kinetic_mini.webp -------------------------------------------------------------------------------- /native/images/objectives/auto rifle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/auto rifle.png -------------------------------------------------------------------------------- /native/images/objectives/final blows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/final blows.png -------------------------------------------------------------------------------- /native/images/objectives/hand cannon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/hand cannon.png -------------------------------------------------------------------------------- /native/images/objectives/lost sector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/lost sector.png -------------------------------------------------------------------------------- /native/images/objectives/machine gun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/machine gun.png -------------------------------------------------------------------------------- /native/images/objectives/pulse rifle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/pulse rifle.png -------------------------------------------------------------------------------- /native/images/objectives/scout rifle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/scout rifle.png -------------------------------------------------------------------------------- /native/images/objectives/trace rifle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/trace rifle.png -------------------------------------------------------------------------------- /native/ios/GuardianGhost/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "expo" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /mono/docs/starlight/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["astro-build.astro-vscode"], 3 | "unwantedRecommendations": [] 4 | } 5 | -------------------------------------------------------------------------------- /native/images/details-masterwork-trim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/details-masterwork-trim.png -------------------------------------------------------------------------------- /native/images/objectives/large blocker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/large blocker.png -------------------------------------------------------------------------------- /native/images/objectives/linear fusion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/linear fusion.png -------------------------------------------------------------------------------- /native/images/objectives/small blocker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/small blocker.png -------------------------------------------------------------------------------- /native/images/objectives/sniper rifle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/sniper rifle.png -------------------------------------------------------------------------------- /mono/docs/starlight/src/assets/houston.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/mono/docs/starlight/src/assets/houston.webp -------------------------------------------------------------------------------- /native/android/WhatsNew/whatsnew-en-US: -------------------------------------------------------------------------------- 1 | 1.3.0 2 | 3 | Supports: 4 | - Fix for missing transfer buttons. 5 | - Update dependencies. 6 | - Bug fixes... 7 | -------------------------------------------------------------------------------- /native/images/icons/inventory-item-tier2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/icons/inventory-item-tier2.png -------------------------------------------------------------------------------- /native/images/icons/inventory-item-tier3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/icons/inventory-item-tier3.png -------------------------------------------------------------------------------- /native/images/icons/inventory-item-tier4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/icons/inventory-item-tier4.png -------------------------------------------------------------------------------- /native/images/icons/inventory-item-tier5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/icons/inventory-item-tier5.png -------------------------------------------------------------------------------- /native/images/objectives/grenade launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/grenade launcher.png -------------------------------------------------------------------------------- /native/images/objectives/medium blocker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/medium blocker.png -------------------------------------------------------------------------------- /native/images/objectives/rocket launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/rocket launcher.png -------------------------------------------------------------------------------- /mono/apps/site/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'astro/config'; 2 | 3 | // https://astro.build/config 4 | export default defineConfig({}); 5 | -------------------------------------------------------------------------------- /native/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "platforms": "universal", 3 | "aliases": { 4 | "components": "@/components", 5 | "lib": "@/lib" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /native/images/masterwork-landscape-overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/masterwork-landscape-overlay.png -------------------------------------------------------------------------------- /mono/apps/site/public/images/google-play-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/mono/apps/site/public/images/google-play-badge.png -------------------------------------------------------------------------------- /mono/docs/starlight/src/assets/guardian-loot.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/mono/docs/starlight/src/assets/guardian-loot.webp -------------------------------------------------------------------------------- /mono/docs/starlight/src/assets/transferSystem.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/mono/docs/starlight/src/assets/transferSystem.webp -------------------------------------------------------------------------------- /native/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /native/ios/TestFlight/WhatToTest.en-US.txt: -------------------------------------------------------------------------------- 1 | 1.3.0 2 | 3 | Supports: 4 | - Fix for missing transfer buttons. 5 | - Update dependencies. 6 | - Liquid glass fixes... -------------------------------------------------------------------------------- /mono/examples/default-project/src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/mono/examples/default-project/src/assets/favicon.ico -------------------------------------------------------------------------------- /native/images/objectives/special grenade launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/images/objectives/special grenade launcher.png -------------------------------------------------------------------------------- /native/ios/GuardianGhost/GuardianGhost-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | -------------------------------------------------------------------------------- /native/eslint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ["eslint-plugin-react-compiler"], 3 | rules: { 4 | "react-compiler/react-compiler": "error", 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /native/ios/sentry.properties: -------------------------------------------------------------------------------- 1 | defaults.url=https://sentry.io/ 2 | defaults.org=nigel-breslaw 3 | defaults.project=guardian-ghost 4 | # Using SENTRY_AUTH_TOKEN environment variable -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "github.vscode-github-actions", 4 | "biomejs.biome", 5 | "astro-build.astro-vscode" 6 | ] 7 | } -------------------------------------------------------------------------------- /native/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /native/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /native/android/sentry.properties: -------------------------------------------------------------------------------- 1 | defaults.url=https://sentry.io/ 2 | defaults.org=nigel-breslaw 3 | defaults.project=guardian-ghost 4 | # Using SENTRY_AUTH_TOKEN environment variable -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/app-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: App issue 3 | about: New items for GG development 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /native/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /native/declaractions.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.svg" { 2 | import type { SvgProps } from "react-native-svg"; 3 | const content: React.FC; 4 | export default content; 5 | } 6 | -------------------------------------------------------------------------------- /native/lib/icons/Check.tsx: -------------------------------------------------------------------------------- 1 | import { Check } from "lucide-react-native"; 2 | import { iconWithClassName } from "./iconWithClassName"; 3 | iconWithClassName(Check); 4 | export { Check }; 5 | -------------------------------------------------------------------------------- /native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /native/lib/icons/Shield.tsx: -------------------------------------------------------------------------------- 1 | import { Shield } from "lucide-react-native"; 2 | import { iconWithClassName } from "./iconWithClassName"; 3 | iconWithClassName(Shield); 4 | export { Shield }; 5 | -------------------------------------------------------------------------------- /native/lib/icons/Swords.tsx: -------------------------------------------------------------------------------- 1 | import { Swords } from "lucide-react-native"; 2 | import { iconWithClassName } from "./iconWithClassName"; 3 | iconWithClassName(Swords); 4 | export { Swords }; 5 | -------------------------------------------------------------------------------- /native/android/app/src/main/res/drawable-hdpi/splashscreen_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/drawable-hdpi/splashscreen_logo.png -------------------------------------------------------------------------------- /native/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png -------------------------------------------------------------------------------- /native/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png -------------------------------------------------------------------------------- /native/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png -------------------------------------------------------------------------------- /native/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png -------------------------------------------------------------------------------- /native/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /native/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /native/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /native/lib/icons/ChevronUp.tsx: -------------------------------------------------------------------------------- 1 | import { ChevronUp } from "lucide-react-native"; 2 | import { iconWithClassName } from "./iconWithClassName"; 3 | iconWithClassName(ChevronUp); 4 | export { ChevronUp }; 5 | -------------------------------------------------------------------------------- /mono/apps/site/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | type Runtime = import("@astrojs/cloudflare").DirectoryRuntime; 3 | declare namespace App { 4 | interface Locals extends Runtime {} 5 | } -------------------------------------------------------------------------------- /mono/docs/starlight/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | 3 | export default defineConfig({ 4 | test: { 5 | coverage: { 6 | reporter: ['lcov'], 7 | }, 8 | }, 9 | }) -------------------------------------------------------------------------------- /native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /native/lib/icons/ChevronDown.tsx: -------------------------------------------------------------------------------- 1 | import { ChevronDown } from "lucide-react-native"; 2 | import { iconWithClassName } from "./iconWithClassName"; 3 | iconWithClassName(ChevronDown); 4 | export { ChevronDown }; 5 | -------------------------------------------------------------------------------- /native/lib/icons/Refresh-ccw.tsx: -------------------------------------------------------------------------------- 1 | import { RefreshCcw } from "lucide-react-native"; 2 | import { iconWithClassName } from "./iconWithClassName"; 3 | iconWithClassName(RefreshCcw); 4 | export { RefreshCcw }; 5 | -------------------------------------------------------------------------------- /native/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /native/ios/GuardianGhost/Images.xcassets/SplashScreenLogo.imageset/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/ios/GuardianGhost/Images.xcassets/SplashScreenLogo.imageset/image.png -------------------------------------------------------------------------------- /native/lib/icons/ChevronRight.tsx: -------------------------------------------------------------------------------- 1 | import { ChevronRight } from "lucide-react-native"; 2 | import { iconWithClassName } from "./iconWithClassName"; 3 | iconWithClassName(ChevronRight); 4 | export { ChevronRight }; 5 | -------------------------------------------------------------------------------- /native/ios/GuardianGhost/Images.xcassets/SplashScreenLogo.imageset/image@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/ios/GuardianGhost/Images.xcassets/SplashScreenLogo.imageset/image@2x.png -------------------------------------------------------------------------------- /native/ios/GuardianGhost/Images.xcassets/SplashScreenLogo.imageset/image@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/ios/GuardianGhost/Images.xcassets/SplashScreenLogo.imageset/image@3x.png -------------------------------------------------------------------------------- /native/ios/GuardianGhost/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NigelBreslaw/guardian-ghost/HEAD/native/ios/GuardianGhost/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "tasks": { 4 | "build": { 5 | "dependsOn": ["^build"], 6 | "outputs": ["dist/**"] 7 | }, 8 | "type-check": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /native/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .expo/ 3 | dist/ 4 | npm-debug.* 5 | *.jks 6 | *.p8 7 | *.p12 8 | *.key 9 | *.mobileprovision 10 | *.orig.* 11 | web-build/ 12 | 13 | # macOS 14 | .DS_Store 15 | 16 | 17 | .env.local 18 | -------------------------------------------------------------------------------- /native/android/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Android/IntelliJ 6 | # 7 | build/ 8 | .idea 9 | .gradle 10 | local.properties 11 | *.iml 12 | *.hprof 13 | .cxx/ 14 | 15 | # Bundle artifacts 16 | *.jsbundle 17 | -------------------------------------------------------------------------------- /mono/docs/starlight/src/content/docs/guides/architecture.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Continuous Integration 3 | description: Details on continuous integration 4 | --- 5 | 6 | ### Transfer 7 | 8 | ![Transfer flow chart](../../../assets/transferSystem.webp) 9 | -------------------------------------------------------------------------------- /mono/examples/default-project/README.md: -------------------------------------------------------------------------------- 1 | ## Usage 2 | 3 | ```bash 4 | $ pnpm install 5 | ``` 6 | 7 | ### More default readme 8 | 9 | A default project, with default scripts for linting and formatting. 10 | It uses SolidJS as the project only takes half a second to build. 11 | -------------------------------------------------------------------------------- /native/metro.config.js: -------------------------------------------------------------------------------- 1 | const { getSentryExpoConfig } = require("@sentry/react-native/metro"); 2 | const { withNativeWind } = require("nativewind/metro"); 3 | const config = getSentryExpoConfig(__dirname); 4 | 5 | module.exports = withNativeWind(config, { input: "./global.css" }); 6 | -------------------------------------------------------------------------------- /native/app/inventory/sections/VaultSpacerUI.tsx: -------------------------------------------------------------------------------- 1 | import { View } from "react-native"; 2 | 3 | type Props = { 4 | readonly size: number; 5 | }; 6 | 7 | export default function VaultSpacer({ size }: Props) { 8 | "use memo"; 9 | return ; 10 | } 11 | -------------------------------------------------------------------------------- /mono/docs/starlight/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "./node_modules/.bin/astro dev", 6 | "name": "Development server", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /native/ios/Podfile.properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo.jsEngine": "hermes", 3 | "EX_DEV_CLIENT_NETWORK_INSPECTOR": "true", 4 | "newArchEnabled": "true", 5 | "expo-image.disable-libdav1d": "false", 6 | "ios.forceStaticLinking": "[]", 7 | "apple.privacyManifestAggregationEnabled": "true" 8 | } 9 | -------------------------------------------------------------------------------- /native/images/svg/twitch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /native/android/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /mono/docs/starlight/src/content/config.ts: -------------------------------------------------------------------------------- 1 | import { defineCollection } from "astro:content"; 2 | import { docsSchema, i18nSchema } from "@astrojs/starlight/schema"; 3 | 4 | export const collections = { 5 | docs: defineCollection({ schema: docsSchema() }), 6 | i18n: defineCollection({ type: "data", schema: i18nSchema() }), 7 | }; 8 | -------------------------------------------------------------------------------- /native/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /native/app/inventory/pages/ArmorPage.tsx: -------------------------------------------------------------------------------- 1 | import { InventoryPageEnums } from "@/app/inventory/logic/Helpers.ts"; 2 | import InventoryPage from "@/app/inventory/pages/InventoryPage.tsx"; 3 | 4 | export default function ArmorPage() { 5 | "use memo"; 6 | return ; 7 | } 8 | -------------------------------------------------------------------------------- /native/app/inventory/pages/GeneralPage.tsx: -------------------------------------------------------------------------------- 1 | import { InventoryPageEnums } from "@/app/inventory/logic/Helpers.ts"; 2 | import InventoryPage from "@/app/inventory/pages/InventoryPage.tsx"; 3 | 4 | export default function GeneralPage() { 5 | "use memo"; 6 | return ; 7 | } 8 | -------------------------------------------------------------------------------- /native/app/inventory/pages/WeaponsPage.tsx: -------------------------------------------------------------------------------- 1 | import { InventoryPageEnums } from "@/app/inventory/logic/Helpers.ts"; 2 | import InventoryPage from "@/app/inventory/pages/InventoryPage.tsx"; 3 | 4 | export default function WeaponsPage() { 5 | "use memo"; 6 | return ; 7 | } 8 | -------------------------------------------------------------------------------- /native/ios/GuardianGhost.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /native/android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #17101F 3 | #ffffff 4 | #023c69 5 | #17101F 6 | #17101F 7 | -------------------------------------------------------------------------------- /native/app/_authenticated/(drawer)/(tabs)/armor.tsx: -------------------------------------------------------------------------------- 1 | import { InventoryPageEnums } from "@/app/inventory/logic/Helpers.ts"; 2 | import InventoryPage from "@/app/inventory/pages/InventoryPage.tsx"; 3 | 4 | export default function ArmorPage() { 5 | "use memo"; 6 | return ; 7 | } 8 | -------------------------------------------------------------------------------- /native/app/_authenticated/(drawer)/(tabs)/weapons.tsx: -------------------------------------------------------------------------------- 1 | import { InventoryPageEnums } from "@/app/inventory/logic/Helpers.ts"; 2 | import InventoryPage from "@/app/inventory/pages/InventoryPage.tsx"; 3 | 4 | export default function WeaponsPage() { 5 | "use memo"; 6 | return ; 7 | } 8 | -------------------------------------------------------------------------------- /native/README.md: -------------------------------------------------------------------------------- 1 | # [New Architecture Example](https://reactnative.dev/docs/the-new-architecture/landing-page) 2 | 3 | ## 🚀 How to use 4 | 5 | > `npx create-expo-app@latest -e with-new-arch` 6 | 7 | - Install packages with `yarn` or `npm install`. 8 | - Run `npx expo run:ios` and/or `npx expo run:android`. Requires native toolchains to be installed. 9 | -------------------------------------------------------------------------------- /native/ios/GuardianGhost/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "filename": "App-Icon-1024x1024@1x.png", 5 | "idiom": "universal", 6 | "platform": "ios", 7 | "size": "1024x1024" 8 | } 9 | ], 10 | "info": { 11 | "version": 1, 12 | "author": "expo" 13 | } 14 | } -------------------------------------------------------------------------------- /native/app/_authenticated/(drawer)/(tabs)/inventory.tsx: -------------------------------------------------------------------------------- 1 | import { InventoryPageEnums } from "@/app/inventory/logic/Helpers.ts"; 2 | import InventoryPage from "@/app/inventory/pages/InventoryPage.tsx"; 3 | 4 | export default function InventoryPageRoute() { 5 | "use memo"; 6 | return ; 7 | } 8 | -------------------------------------------------------------------------------- /native/app/UI/Text.tsx: -------------------------------------------------------------------------------- 1 | // Temp hack for now to stop text scaling 2 | import { Text as RNText } from "react-native"; 3 | 4 | type Props = React.ComponentProps; 5 | 6 | export default function Text({ children, ...props }: Props) { 7 | return ( 8 | 9 | {children} 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /native/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Guardian Ghost 3 | dark 4 | contain 5 | false 6 | -------------------------------------------------------------------------------- /native/lib/icons/iconWithClassName.ts: -------------------------------------------------------------------------------- 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 | } 15 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": [ 3 | "node_modules/.cache", 4 | ".expo", 5 | "android/.gradle", 6 | "android/app/build", 7 | "ios/build", 8 | "ios/DerivedData", 9 | "native/.expo", 10 | "native/android/.gradle", 11 | "native/android/app/build", 12 | "native/ios/build", 13 | "native/ios/DerivedData" 14 | ] 15 | } -------------------------------------------------------------------------------- /native/ios/GuardianGhost/GuardianGhost.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.associated-domains 6 | 7 | applinks:app.guardianghost.com 8 | 9 | 10 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - native 3 | - mono/apps/* 4 | - mono/docs/* 5 | - mono/examples/* 6 | 7 | catalog: 8 | '@biomejs/biome': 2.3.7 9 | astro: 5.16.4 10 | turbo: 2.6.1 11 | typescript: 5.9.3 12 | 13 | onlyBuiltDependencies: 14 | - '@sentry/cli' 15 | - esbuild 16 | - sharp 17 | 18 | patchedDependencies: 19 | '@gorhom/bottom-sheet': patches/@gorhom__bottom-sheet.patch 20 | -------------------------------------------------------------------------------- /native/lib/useColorScheme.tsx: -------------------------------------------------------------------------------- 1 | import { useColorScheme as useNativewindColorScheme } from "nativewind"; 2 | 3 | export function useColorScheme() { 4 | const { colorScheme, setColorScheme, toggleColorScheme } = useNativewindColorScheme(); 5 | return { 6 | colorScheme: colorScheme ?? "dark", 7 | isDarkColorScheme: colorScheme === "dark", 8 | setColorScheme, 9 | toggleColorScheme, 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /native/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /native/android/app/src/debugOptimized/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /mono/examples/default-project/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: 4 | -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", 5 | "Helvetica Neue", sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; 12 | } 13 | -------------------------------------------------------------------------------- /native/images/svg/ellipses-horizontal.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /native/ios/GuardianGhost/Supporting/Expo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | EXUpdatesCheckOnLaunch 6 | ALWAYS 7 | EXUpdatesEnabled 8 | 9 | EXUpdatesLaunchWaitMs 10 | 0 11 | 12 | -------------------------------------------------------------------------------- /native/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | return { 4 | presets: [["babel-preset-expo", { jsxImportSource: "nativewind" }], "nativewind/babel"], 5 | plugins: [ 6 | [ 7 | "babel-plugin-react-compiler", 8 | { 9 | compilationMode: "annotation", 10 | target: "19", 11 | }, 12 | ], 13 | "react-native-worklets/plugin", 14 | ], 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /mono/examples/default-project/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "allowSyntheticDefaultImports": true, 8 | "esModuleInterop": true, 9 | "jsx": "preserve", 10 | "jsxImportSource": "solid-js", 11 | "types": ["vite/client"], 12 | "noEmit": true, 13 | "isolatedModules": true 14 | }, 15 | "include": ["src"] 16 | } 17 | -------------------------------------------------------------------------------- /native/ios/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | .xcode.env.local 25 | 26 | # Bundle artifacts 27 | *.jsbundle 28 | 29 | # CocoaPods 30 | /Pods/ 31 | -------------------------------------------------------------------------------- /native/eas.json: -------------------------------------------------------------------------------- 1 | { 2 | "build": { 3 | "development": { 4 | "developmentClient": true, 5 | "distribution": "internal" 6 | }, 7 | "preview": { 8 | "distribution": "internal" 9 | }, 10 | "development-simulator": { 11 | "developmentClient": true, 12 | "distribution": "internal", 13 | "ios": { 14 | "simulator": true 15 | } 16 | }, 17 | "production": {} 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /native/constants/Colors.ts: -------------------------------------------------------------------------------- 1 | const tintColorLight = "#2f95dc"; 2 | const tintColorDark = "#fff"; 3 | 4 | export default { 5 | light: { 6 | text: "#000", 7 | background: "#fff", 8 | tint: tintColorLight, 9 | tabIconDefault: "#ccc", 10 | tabIconSelected: tintColorLight, 11 | }, 12 | dark: { 13 | text: "#fff", 14 | background: "#000", 15 | tint: tintColorDark, 16 | tabIconDefault: "#ccc", 17 | tabIconSelected: tintColorDark, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /mono/examples/default-project/src/index.tsx: -------------------------------------------------------------------------------- 1 | /* @refresh reload */ 2 | import { render } from "solid-js/web"; 3 | 4 | import "./index.css"; 5 | import App from "./App"; 6 | 7 | const root = document.getElementById("root"); 8 | 9 | if (import.meta.env.DEV && !(root instanceof HTMLElement)) { 10 | throw new Error( 11 | "Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?", 12 | ); 13 | } 14 | 15 | render(() => , root!); 16 | -------------------------------------------------------------------------------- /native/ios/GuardianGhost/Images.xcassets/SplashScreenBackground.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors": [ 3 | { 4 | "color": { 5 | "components": { 6 | "alpha": "1.000", 7 | "blue": "0.121568627450980", 8 | "green": "0.0627450980392157", 9 | "red": "0.0901960784313725" 10 | }, 11 | "color-space": "srgb" 12 | }, 13 | "idiom": "universal" 14 | } 15 | ], 16 | "info": { 17 | "version": 1, 18 | "author": "expo" 19 | } 20 | } -------------------------------------------------------------------------------- /native/public/.well-known/assetlinks.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "relation": ["delegate_permission/common.handle_all_urls"], 4 | "target": { 5 | "namespace": "android_app", 6 | "package_name": "com.guardianghost", 7 | "sha256_cert_fingerprints": [ 8 | "03:8C:FF:63:6D:B2:BB:00:0D:37:4D:AF:D3:37:CC:CA:48:9B:BF:33:0B:EB:91:86:20:79:80:16:AE:E9:B2:FB", 9 | "FA:C6:17:45:DC:09:03:78:6F:B9:ED:E6:2A:96:2B:39:9F:73:48:F0:BB:6F:89:9B:83:32:66:75:91:03:3B:9C" 10 | ] 11 | } 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /native/ios/GuardianGhost/Images.xcassets/SplashScreenLogo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "universal", 5 | "filename": "image.png", 6 | "scale": "1x" 7 | }, 8 | { 9 | "idiom": "universal", 10 | "filename": "image@2x.png", 11 | "scale": "2x" 12 | }, 13 | { 14 | "idiom": "universal", 15 | "filename": "image@3x.png", 16 | "scale": "3x" 17 | } 18 | ], 19 | "info": { 20 | "version": 1, 21 | "author": "expo" 22 | } 23 | } -------------------------------------------------------------------------------- /native/app/_authenticated/(drawer)/settings.tsx: -------------------------------------------------------------------------------- 1 | import Settings from "@/app/screens/Settings.tsx"; 2 | import { Stack } from "expo-router"; 3 | 4 | export default function SettingsScreen() { 5 | "use memo"; 6 | return ( 7 | <> 8 | 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /native/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /native/app/_authenticated/(drawer)/search.tsx: -------------------------------------------------------------------------------- 1 | import SearchView from "@/app/inventory/pages/SearchView.tsx"; 2 | import { Stack } from "expo-router"; 3 | 4 | export default function SearchScreen() { 5 | "use memo"; 6 | return ( 7 | <> 8 | 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /native/images/shield.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | .astro/ 14 | *.local 15 | coverage 16 | 17 | # Editor directories and files 18 | .vscode/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | .turbo 28 | 29 | # environment variables 30 | .env 31 | .env.production 32 | native/ios/GuardianGhost.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist 33 | -------------------------------------------------------------------------------- /mono/apps/site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app-showcase", 3 | "type": "module", 4 | "version": "0.0.1", 5 | "scripts": { 6 | "dev": "astro dev", 7 | "start": "astro dev", 8 | "build": "astro build", 9 | "build:ci": "turbo build --remote-only --api=$TURBO_URL --token=$TURBO_CODE --team=CI", 10 | "preview": "astro preview", 11 | "astro": "astro" 12 | }, 13 | "dependencies": { 14 | "astro": "catalog:", 15 | "turbo": "catalog:" 16 | }, 17 | "devDependencies": { 18 | "@biomejs/biome": "catalog:" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /native/images/sword.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /mono/docs/starlight/src/content/docs/guides/costs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Costs 3 | description: Current yearly tool and hosting costs for developing Guardian Ghost 4 | --- 5 | 6 | ### Hosting 7 | Source code: Github (free) 8 | 9 | Web apps: Cloudflare Pages (free) 10 | 11 | 12 | ### App Stores and SDK 13 | Windows and Android are either free or were a one off fee paid years ago. 14 | Apple (iOS and MacOS): $99 a year. 15 | 16 | Github Copilot is $10 a month. 17 | 18 | 19 | ### Domain registration 20 | .com and .app yearly fees are ~$20 a year 21 | 22 | # Yearly total 23 | $240 24 | -------------------------------------------------------------------------------- /minifier/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "definition_minifier", 3 | "version": "0.0.0", 4 | "main": "index.ts", 5 | "scripts": { 6 | "start": "bun run next_gen.ts", 7 | "benchmark": "bun run benchmark.ts", 8 | "benchmark:baseline": "bun run benchmark.ts --baseline", 9 | "benchmark:compare": "bun run benchmark.ts --compare", 10 | "verify:baseline": "bun run verify-output.ts --save-baseline", 11 | "verify:compare": "bun run verify-output.ts --compare" 12 | }, 13 | "devDependencies": { 14 | "@types/bun": "1.3.0", 15 | "typescript": "5.9.3" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /mono/examples/default-project/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import solidPlugin from 'vite-plugin-solid'; 3 | // import devtools from 'solid-devtools/vite'; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | /* 8 | Uncomment the following line to enable solid-devtools. 9 | For more info see https://github.com/thetarnav/solid-devtools/tree/main/packages/extension#readme 10 | */ 11 | // devtools(), 12 | solidPlugin(), 13 | ], 14 | server: { 15 | port: 3000, 16 | }, 17 | build: { 18 | target: 'esnext', 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Guardian Ghost", 3 | "version": "1.2.0", 4 | "description": "", 5 | "scripts": { 6 | "format": "biome format biome.json && pnpm --stream -r format", 7 | "format:fix": "biome format biome.json --write && pnpm --stream -r format:fix", 8 | "lint": "pnpm --stream -r lint", 9 | "lint:fix": "pnpm --stream -r lint:fix", 10 | "type-check": "pnpm --stream -r type-check", 11 | "build:ci": "pnpm --stream -r build:ci" 12 | }, 13 | "devDependencies": { 14 | "@biomejs/biome": "catalog:" 15 | }, 16 | "packageManager": "pnpm@10.20.0" 17 | } 18 | -------------------------------------------------------------------------------- /mono/examples/default-project/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Solid App 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /native/images/package.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /mono/docs/starlight/src/content/docs/guides/misc.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Misc 3 | description: Details on previous tech trials 4 | --- 5 | 6 | December 2023: I did try to use [Bun](https://bun.sh/) which limits development to Linux and MacOS with Windows support only on [WSL](https://learn.microsoft.com/en-us/windows/wsl/about). However the monorepo and full node ecosystem support isn't quite there yet. Thus Node and [Pnpm](https://pnpm.io) are used instead. CI runs as of 25.12.2023 are ~25 seconds with PNPM and probably would be 5-8 seconds faster with Bun. I will revisit Bun later in 2024 when its compatibility and Monorepo support improves. -------------------------------------------------------------------------------- /native/app/store/Types.ts: -------------------------------------------------------------------------------- 1 | import type { DefinitionKey } from "@/app/core/BungieDefinitions.ts"; 2 | 3 | export type AsyncStorageKey = 4 | | DefinitionKey 5 | | "CACHED_PROFILE" 6 | | "ITEM_DEFINITION" 7 | | "ACCOUNTS" 8 | | "REFRESH_TOKEN" 9 | | "BUNGIE_USER"; 10 | 11 | export enum WeaponsSort { 12 | Power = "POWER", 13 | Type = "TYPE", 14 | TypeAndPower = "TYPE_AND_POWER", 15 | } 16 | 17 | export enum ArmorSort { 18 | Power = "POWER", 19 | Type = "TYPE", 20 | } 21 | 22 | export const DatabaseStore = { 23 | factoryName: "gg-data", 24 | storeName: "key-values", 25 | databaseName: "ggDataBase.db", 26 | }; 27 | -------------------------------------------------------------------------------- /cSpell.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePaths": [ 3 | "**/*.pbxproj", 4 | "**/*.lock", 5 | "cspell.json" 6 | ], 7 | "words": [ 8 | "Bnet", 9 | "clsx", 10 | "Deepsight", 11 | "dvwi", 12 | "equippable", 13 | "gorhom", 14 | "headshot", 15 | "Ionicons", 16 | "lucide", 17 | "masterworked", 18 | "MMKV", 19 | "Nativewind", 20 | "reusables", 21 | "seraphite", 22 | "spawnfx", 23 | "Stackable", 24 | "Subviews", 25 | "Synthcord", 26 | "Synthstrand", 27 | "tailwindcss", 28 | "Unequip", 29 | "Uninstanced", 30 | "Unlockable", 31 | "vthorn" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /native/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # react-native-reanimated 11 | -keep class com.swmansion.reanimated.** { *; } 12 | -keep class com.facebook.react.turbomodule.** { *; } 13 | 14 | # Add any project specific keep options here: 15 | -------------------------------------------------------------------------------- /native/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Guardian Ghost", 3 | "name": "Guardian Ghost", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": "https://app.guardianghost.com", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /mono/examples/default-project/src/App.module.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .logo { 6 | animation: logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | pointer-events: none; 9 | } 10 | 11 | .header { 12 | background-color: #282c34; 13 | min-height: 100vh; 14 | display: flex; 15 | flex-direction: column; 16 | align-items: center; 17 | justify-content: center; 18 | font-size: calc(10px + 2vmin); 19 | color: white; 20 | } 21 | 22 | .link { 23 | color: #b318f0; 24 | } 25 | 26 | @keyframes logo-spin { 27 | from { 28 | transform: rotate(0deg); 29 | } 30 | to { 31 | transform: rotate(360deg); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/main-mono.yml: -------------------------------------------------------------------------------- 1 | name: main-ci-mono 2 | 3 | on: 4 | push: 5 | 6 | jobs: 7 | main-ci-mono: 8 | name: Main CI Mono 9 | timeout-minutes: 5 10 | runs-on: ubuntu-latest 11 | 12 | env: 13 | TURBO_URL: ${{ secrets.TURBO_URL }} 14 | TURBO_CODE: ${{ secrets.TURBO_CODE }} 15 | 16 | steps: 17 | - uses: actions/checkout@v6.0.1 18 | - uses: pnpm/action-setup@v4.2.0 19 | with: 20 | version: 10.20.0 21 | - name: install dependencies 22 | run: pnpm install --frozen-lockfile 23 | - name: type check 24 | run: pnpm type-check 25 | - name: build 26 | run: pnpm build:ci 27 | -------------------------------------------------------------------------------- /native/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath('com.android.tools.build:gradle') 10 | classpath('com.facebook.react:react-native-gradle-plugin') 11 | classpath('org.jetbrains.kotlin:kotlin-gradle-plugin') 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | google() 18 | mavenCentral() 19 | maven { url 'https://www.jitpack.io' } 20 | } 21 | } 22 | 23 | apply plugin: "expo-root-project" 24 | apply plugin: "com.facebook.react.rootproject" 25 | -------------------------------------------------------------------------------- /native/images/svg/psn.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mono/examples/default-project/src/App.tsx: -------------------------------------------------------------------------------- 1 | import type { Component } from "solid-js"; 2 | 3 | import logo from "./logo.svg"; 4 | import styles from "./App.module.css"; 5 | 6 | const App: Component = () => { 7 | return ( 8 |
9 |
10 | logo 11 |

12 | Edit src/App.tsx and save to reload. 13 |

14 | 15 | Learn Solid 16 | 17 |
18 |
19 | ); 20 | }; 21 | 22 | export default App; 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Guardian Ghost monorepo 2 | 3 | As of December 2023 this is a monorepo built around going beyond the Ishtar Commander mobile applications. 4 | 5 | The tech choices are based on interesting new tools to learn. However the main app will use React-Native. 6 | 7 | ## Developer environment 8 | 9 | Full documentation and details about the project can be found [here](https://docs.guardianghost.com). 10 | 11 | ## Main deployments 12 | 13 | Landing/Marketing page [guardianghost.com](https://guardianghost.com) 14 | 15 | Web app site (Mobile only!!, desktop will come later) [app.guardianghost.com](https://app.guardianghost.com) 16 | 17 | Documentation [docs.guardianghost.com](https://docs.guardianghost.com) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /mono/docs/starlight/public/favicon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /minifier/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": ["ESNext"], 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleDetection": "force", 8 | "jsx": "react-jsx", 9 | "allowJs": true, 10 | 11 | // Bundler mode 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "verbatimModuleSyntax": true, 15 | "noEmit": true, 16 | 17 | // Best practices 18 | "strict": true, 19 | "skipLibCheck": true, 20 | "noFallthroughCasesInSwitch": true, 21 | 22 | // Some stricter flags 23 | "noUnusedLocals": true, 24 | "noUnusedParameters": true, 25 | "noPropertyAccessFromIndexSignature": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /native/public/.well-known/apple-app-site-association: -------------------------------------------------------------------------------- 1 | { 2 | "applinks": { 3 | "details": [ 4 | { 5 | "appIDs": ["X2Z8M625Y9.com.guardianghost.mobile"], 6 | "components": [ 7 | { 8 | "#": "no_universal_links", 9 | "exclude": true, 10 | "comment": "Matches any URL with a fragment that equals no_universal_links and instructs the system not to open it as a universal link." 11 | }, 12 | { 13 | "/": "/auth", 14 | "comment": "Matches a URL with a path that starts with /auth." 15 | } 16 | ] 17 | } 18 | ] 19 | }, 20 | "webcredentials": { 21 | "apps": ["X2Z8M625Y9.com.guardianghost.mobile"] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /native/constants/env.ts: -------------------------------------------------------------------------------- 1 | import { Platform } from "react-native"; 2 | 3 | export const isLocalWeb = process.env.NODE_ENV === "development" && Platform.OS === "web"; 4 | // @ts-ignore 5 | export const apiKey: string = !isLocalWeb ? process.env.EXPO_PUBLIC_API_KEY : process.env.EXPO_PUBLIC_API_KEY_WEB; 6 | // @ts-ignore 7 | export const clientID: string = !isLocalWeb ? process.env.EXPO_PUBLIC_CLIENT_ID : process.env.EXPO_PUBLIC_CLIENT_ID_WEB; 8 | // @ts-ignore 9 | export const clientSecret: string = !isLocalWeb 10 | ? process.env.EXPO_PUBLIC_CLIENT_SECRET 11 | : process.env.EXPO_PUBLIC_CLIENT_SECRET_WEB; 12 | 13 | export const redirectURL = 14 | Platform.OS === "web" ? "https://app.guardianghost.com/oauth" : "https://app.guardianghost.com/auth"; 15 | -------------------------------------------------------------------------------- /mono/apps/site/public/images/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /native/app/inventory/sections/ArtifactUI.tsx: -------------------------------------------------------------------------------- 1 | import { View, StyleSheet } from "react-native"; 2 | 3 | import ArtifactCell from "@/app/inventory/cells/ArtifactCell.tsx"; 4 | import { DEFAULT_SECTION_4_WIDTH, ICON_MARGIN, ICON_SIZE } from "@/app/utilities/UISize.ts"; 5 | import type { DestinyItem } from "@/app/inventory/logic/Types.ts"; 6 | 7 | type Props = { 8 | readonly item: DestinyItem | undefined; 9 | }; 10 | 11 | export default function ArtifactUI({ item }: Props) { 12 | "use memo"; 13 | return ( 14 | 15 | 16 | 17 | ); 18 | } 19 | 20 | const styles = StyleSheet.create({ 21 | container: { 22 | width: DEFAULT_SECTION_4_WIDTH, 23 | height: ICON_SIZE + ICON_MARGIN, 24 | alignSelf: "center", 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /native/global.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 240 10% 3.9%; 8 | --foreground: 0 0% 98%; 9 | --card: 240 10% 3.9%; 10 | --card-foreground: 0 0% 98%; 11 | --popover: 240 10% 3.9%; 12 | --popover-foreground: 0 0% 98%; 13 | --primary: 0 0% 98%; 14 | --primary-foreground: 0 5.9% 10%; 15 | --secondary: 0 3.7% 15.9%; 16 | --secondary-foreground: 0 0% 98%; 17 | --muted: 240 3.7% 15.9%; 18 | --muted-foreground: 240 5% 64.9%; 19 | --accent: 240 3.7% 15.9%; 20 | --accent-foreground: 0 0% 98%; 21 | --destructive: 0 72% 51%; 22 | --destructive-foreground: 0 0% 98%; 23 | --border: 240 3.7% 15.9%; 24 | --input: 240 3.7% 15.9%; 25 | --ring: 240 4.9% 83.9%; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /native/components/ui/text.tsx: -------------------------------------------------------------------------------- 1 | import * as Slot from "@rn-primitives/slot"; 2 | import type { SlottableTextProps, TextRef } from "@rn-primitives/types"; 3 | import * as React from "react"; 4 | import { Text as RNText } from "react-native"; 5 | import { cn } from "@/lib/utils"; 6 | 7 | const TextClassContext = React.createContext(undefined); 8 | 9 | const Text = React.forwardRef(({ className, asChild = false, ...props }, ref) => { 10 | const textClass = React.useContext(TextClassContext); 11 | const Component = asChild ? Slot.Text : RNText; 12 | return ( 13 | 14 | ); 15 | }); 16 | Text.displayName = "Text"; 17 | 18 | export { Text, TextClassContext }; 19 | -------------------------------------------------------------------------------- /native/images/svg/steam.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /native/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "expo/tsconfig.base", 3 | "compilerOptions": { 4 | "allowImportingTsExtensions": true, 5 | "noEmit": true, 6 | "noUncheckedIndexedAccess": true, 7 | "noErrorTruncation": true, 8 | "lib": [ 9 | "DOM", 10 | "ESNext", 11 | "es2019", 12 | "es2020.bigint", 13 | "es2020.date", 14 | "es2020.number", 15 | "es2020.promise", 16 | "es2020.string", 17 | "es2020.symbol.wellknown", 18 | "es2021.promise", 19 | "es2021.string", 20 | "es2021.weakref", 21 | "es2022.array", 22 | "es2022.object", 23 | "es2022.string" 24 | ], 25 | "baseUrl": ".", 26 | "paths": { 27 | "@/*": ["./*", "./app/*"] 28 | }, 29 | "strict": true 30 | }, 31 | "include": ["**/*.ts", "**/*.tsx", "nativewind-env.d.ts"] 32 | } 33 | -------------------------------------------------------------------------------- /native/app/index.js: -------------------------------------------------------------------------------- 1 | import "react-native-gesture-handler"; // Avoid crash in production https://reactnavigation.org/docs/stack-navigator/#installation 2 | import * as Sentry from "@sentry/react-native"; 3 | import { registerRootComponent } from "expo"; 4 | import { Text, TextInput } from "react-native"; 5 | Text.defaultProps = Text.defaultProps || {}; 6 | Text.defaultProps.allowFontScaling = false; 7 | 8 | TextInput.defaultProps = Text.defaultProps || {}; 9 | TextInput.defaultProps.allowFontScaling = false; 10 | 11 | import Root from "./Root.tsx"; 12 | 13 | Sentry.init({ 14 | dsn: "https://7db2c06ee6ea56cae40a5bd963bad76b@o4506899216728065.ingest.us.sentry.io/4506899221970944", 15 | }); 16 | 17 | // registerRootComponent calls AppRegistry.registerComponent('main', () => App); 18 | // It also ensures that whether you load the app in Expo Go or in a native build, 19 | // the environment is set up appropriately 20 | registerRootComponent(Sentry.wrap(Root)); 21 | -------------------------------------------------------------------------------- /mono/examples/default-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-template-solid", 3 | "version": "0.0.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "vite", 7 | "dev": "vite", 8 | "build": "vite build", 9 | "build:ci": "turbo build --remote-only --api=$TURBO_URL --token=$TURBO_CODE --team=CI", 10 | "coverage": "vitest run --coverage", 11 | "format": "biome format ./src", 12 | "format:fix": "biome format --write ./src", 13 | "lint": "biome lint ./src", 14 | "lint:fix": "biome lint --fix ./src", 15 | "preview": "vite preview", 16 | "type-check": "tsc", 17 | "serve": "vite preview" 18 | }, 19 | "license": "MIT", 20 | "devDependencies": { 21 | "@biomejs/biome": "catalog:", 22 | "solid-devtools": "0.34.4", 23 | "typescript": "catalog:", 24 | "vite": "7.2.4", 25 | "vite-plugin-solid": "2.11.10", 26 | "turbo": "catalog:" 27 | }, 28 | "dependencies": { 29 | "solid-js": "1.9.10" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /native/images/svg/xbox.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /native/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 15 | -------------------------------------------------------------------------------- /native/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import * as LabelPrimitive from "@rn-primitives/label"; 2 | import * as React from "react"; 3 | import { cn } from "@/lib/utils.ts"; 4 | const Label = React.forwardRef< 5 | React.ElementRef, 6 | React.ComponentPropsWithoutRef 7 | >(({ className, onPress, onLongPress, onPressIn, onPressOut, ...props }, ref) => ( 8 | 15 | 23 | 24 | )); 25 | Label.displayName = LabelPrimitive.Root.displayName; 26 | export { Label }; 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /mono/docs/starlight/src/content/docs/guides/todo.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: To-do's 3 | description: Long term to-do's 4 | --- 5 | 6 | I prefer to keep the github issues as clean as possible. For certain types of todo, 7 | such as those where I am waiting on a new feature with no clear date I will store them here. 8 | 9 | 10 | - [ ] When possible move the react-native project into the PNPM workspaces. It's a future plan of Expo and react-native. 11 | - [ ] Github action to check documentation for dead links. See [here](https://docs.github.com/en/actions/examples/using-the-github-cli-on-a-runner). 12 | - [ ] Android signing action is outdated and no longer [maintained](https://github.com/r0adkll/sign-android-release). 13 | - [ ] Trial a remote gradle cache. 14 | - [ ] Trial a shared ccache, scache? 15 | - [ ] Look at adding [Codspeed](https://codspeed.io/blog) for CI based benchmarking 16 | - [ ] Dev helper bash script: Create a bash script that checks you have the right version of various tools such as git, xcode, etc and clones and sets everything up for you. 17 | -------------------------------------------------------------------------------- /mono/docs/starlight/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@gg-monorepo/starlight", 3 | "version": "0.0.1", 4 | "dependencies": { 5 | "@astrojs/starlight": "0.37.0", 6 | "astro": "catalog:", 7 | "rehype": "13.0.2", 8 | "sharp": "0.34.5" 9 | }, 10 | "devDependencies": { 11 | "@biomejs/biome": "catalog:", 12 | "@astrojs/check": "0.9.6", 13 | "@vitest/coverage-v8": "4.0.15", 14 | "typescript": "catalog:", 15 | "vitest": "4.0.15", 16 | "turbo": "catalog:" 17 | }, 18 | "scripts": { 19 | "astro": "astro", 20 | "build": "astro build", 21 | "build:ci": "turbo build --remote-only --api=$TURBO_URL --token=$TURBO_CODE --team=CI", 22 | "coverage": "vitest run --coverage", 23 | "dev": "astro dev", 24 | "format": "biome format ./src", 25 | "format:fix": "biome format --write ./src", 26 | "lint": "biome lint ./src", 27 | "lint:fix": "biome lint --fix ./src", 28 | "preview": "astro preview", 29 | "start": "astro dev", 30 | "type-check": "astro check" 31 | }, 32 | "type": "module" 33 | } 34 | -------------------------------------------------------------------------------- /native/knip.config.ts: -------------------------------------------------------------------------------- 1 | import type { KnipConfig } from "knip"; 2 | 3 | const config: KnipConfig = { 4 | entry: [ 5 | // Expo Router entry point - expo-router/entry handles routing 6 | // Route files in app/ are automatically entry points 7 | ], 8 | project: [ 9 | // All TypeScript/TSX files in app directory 10 | "app/**/*.{ts,tsx}", 11 | // Component files 12 | "components/**/*.{ts,tsx}", 13 | // Library files 14 | "lib/**/*.{ts,tsx}", 15 | ], 16 | ignore: [ 17 | // Native platform code 18 | "android/**", 19 | "ios/**", 20 | // Dependencies 21 | "node_modules/**", 22 | // Build outputs 23 | "**/build/**", 24 | "**/dist/**", 25 | // Test files (if any) 26 | "**/*.test.{ts,tsx}", 27 | "**/*.spec.{ts,tsx}", 28 | // Config files 29 | "**/*.config.{js,ts}", 30 | "babel.config.js", 31 | "metro.config.js", 32 | "tailwind.config.js", 33 | // Public assets 34 | "public/**", 35 | "assets/**", 36 | "images/**", 37 | // Generated files 38 | "app/core/generated/**", 39 | ], 40 | }; 41 | 42 | export default config; 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Nigel Breslaw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/deploy-gg-landing.yml: -------------------------------------------------------------------------------- 1 | name: deploy-gg-landing-site 2 | 3 | on: 4 | push: 5 | paths: 6 | - "mono/apps/site/**" 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | env: 12 | TURBO_URL: ${{ secrets.TURBO_URL }} 13 | TURBO_CODE: ${{ secrets.TURBO_CODE }} 14 | defaults: 15 | run: 16 | working-directory: mono 17 | permissions: 18 | contents: read 19 | deployments: write 20 | name: Deploy 21 | steps: 22 | - uses: actions/checkout@v6.0.1 23 | - uses: pnpm/action-setup@v4.2.0 24 | with: 25 | version: 10.20.0 26 | - name: install dependencies 27 | run: pnpm install --frozen-lockfile 28 | - name: build 29 | run: cd apps/site && pnpm build:ci 30 | - name: publish docs 31 | uses: cloudflare/pages-action@v1.5.0 32 | with: 33 | apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} 34 | accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} 35 | projectName: gg-landing-site 36 | directory: mono/apps/site/dist 37 | gitHubToken: ${{ secrets.GITHUB_TOKEN }} 38 | -------------------------------------------------------------------------------- /native/app/inventory/sections/LootItemRow.tsx: -------------------------------------------------------------------------------- 1 | import { View } from "react-native"; 2 | 3 | import { DEFAULT_MARGIN, ICON_MARGIN, ICON_SIZE, INV_MAX_WIDTH } from "@/app/utilities/UISize.ts"; 4 | import type { DestinyItem } from "@/app/inventory/logic/Types.ts"; 5 | import DestinyCell from "@/app/inventory/cells/DestinyCell.tsx"; 6 | 7 | type Props = { 8 | readonly items: DestinyItem[]; 9 | }; 10 | 11 | export default function LootItemRow({ items }: Props) { 12 | "use memo"; 13 | return ( 14 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /mono/docs/starlight/src/content/docs/guides/infrastructure.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Infrastructure 3 | description: Tech stack 4 | --- 5 | 6 | ### Source Control and Issue tracking 7 | 8 | [Github](https://github.com) is used to host all the code and issue/bug tracking. 9 | 10 | ### CI 11 | 12 | [Github Actions](https://github.com/features/actions) are used to run the CI. 13 | 14 | ### Dependancy Updating 15 | 16 | [Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates) is used to keep all dependencies upto date. It checks 17 | daily for updates to the Github Actions and NPM packages. This ensures the project stays on 18 | top of updates that cover security, bugs and enhancements. 19 | 20 | 21 | ### Security 22 | 23 | [CodeQL](https://codeql.github.com/) runs on every push, PR and on a schedule of once a week. This 24 | checks for security vulnerabilities in any of the code. 25 | 26 | 27 | ### Code Quality 28 | 29 | Locally and in CI [Biome](https://biomejs.dev/) is used to enforce standard code formatting. Biome is also used in place of 30 | eslint to lint the code. 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /native/app/inventory/pages/ResultsSectionUI.tsx: -------------------------------------------------------------------------------- 1 | import { View } from "react-native"; 2 | 3 | import DestinyCell from "@/app/inventory/cells/DestinyCell.tsx"; 4 | import type { DestinyItem } from "@/app/inventory/logic/Types.ts"; 5 | import { ICON_MARGIN, ICON_SIZE } from "@/app/utilities/UISize.ts"; 6 | 7 | export type ResultsSection = { 8 | id: string; 9 | items: DestinyItem[]; 10 | }; 11 | 12 | type ResultsSectionUIProps = { 13 | readonly items: DestinyItem[]; 14 | }; 15 | 16 | export default function ResultsSectionUI({ items }: ResultsSectionUIProps) { 17 | "use memo"; 18 | return ( 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /mono/docs/starlight/src/content/docs/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: GG Guardian Ghost docs 3 | description: Built using Astro Starlight 4 | template: splash 5 | hero: 6 | tagline: Developer focused documentation 7 | image: 8 | file: ../../assets/guardian-loot.webp 9 | actions: 10 | - text: Getting started 11 | link: /guides/monorepo 12 | icon: right-arrow 13 | variant: primary 14 | - text: Visit the main Guardian Ghost page 15 | link: https://guardianghost.com 16 | icon: external 17 | --- 18 | 19 | import { Card, CardGrid } from '@astrojs/starlight/components'; 20 | 21 | ## Next steps 22 | 23 | 24 | 25 | Edit `src/content/docs/index.mdx` to see this page change. 26 | 27 | 28 | Document the monorepo and cloudflare configs. 29 | 30 | 31 | Edit your `sidebar` and other config in `astro.config.mjs`. 32 | 33 | 34 | Learn more in [the Starlight Docs](https://starlight.astro.build/). 35 | 36 | 37 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | paths: 4 | - "mono/docs/**" 5 | 6 | concurrency: 7 | group: ${{ github.workflow }}-${{ github.ref }} 8 | cancel-in-progress: true 9 | 10 | jobs: 11 | deploy: 12 | runs-on: ubuntu-latest 13 | env: 14 | TURBO_URL: ${{ secrets.TURBO_URL }} 15 | TURBO_CODE: ${{ secrets.TURBO_CODE }} 16 | defaults: 17 | run: 18 | working-directory: mono 19 | permissions: 20 | contents: read 21 | deployments: write 22 | name: Deploy 23 | steps: 24 | - uses: actions/checkout@v6.0.1 25 | - uses: pnpm/action-setup@v4.2.0 26 | with: 27 | version: 10.20.0 28 | - name: install dependencies 29 | run: pnpm install --frozen-lockfile 30 | - name: build 31 | run: cd docs/starlight && pnpm build:ci 32 | - name: publish docs 33 | uses: cloudflare/pages-action@v1.5.0 34 | with: 35 | apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} 36 | accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} 37 | projectName: gg-docs 38 | directory: mono/docs/starlight/dist # e.g. 'dist' 39 | gitHubToken: ${{ secrets.GITHUB_TOKEN }} 40 | -------------------------------------------------------------------------------- /native/app/stats/PerkCircle.tsx: -------------------------------------------------------------------------------- 1 | import { TouchableOpacity, View } from "react-native"; 2 | import { Image } from "expo-image"; 3 | 4 | import { ENHANCED_TRAIT } from "@/app/utilities/Constants.ts"; 5 | 6 | type Props = { 7 | readonly icon: string | undefined; 8 | readonly isEnabled: boolean; 9 | readonly isEnhanced: boolean; 10 | readonly onPress: () => void; 11 | }; 12 | 13 | export default function PerkCircle({ icon, isEnabled, isEnhanced, onPress }: Props) { 14 | "use memo"; 15 | return ( 16 | 17 | 29 | 30 | {isEnhanced && ( 31 | 32 | )} 33 | 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /native/app/inventory/sections/EngramsUI.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, View } from "react-native"; 2 | 3 | import { ENGRAMS_SECTION_WIDTH, ENGRAMS_SECTION_HEIGHT, DEFAULT_MARGIN } from "@/app/utilities/UISize.ts"; 4 | import type { DestinyItem } from "@/app/inventory/logic/Types.ts"; 5 | import EngramCell from "@/app/inventory/cells/EngramCell.tsx"; 6 | 7 | const array10 = Array.from({ length: 10 }); 8 | 9 | type Props = { 10 | readonly items: DestinyItem[]; 11 | }; 12 | 13 | export default function EngramsUI({ items }: Props) { 14 | "use memo"; 15 | return ( 16 | 17 | {array10.map((_v, index) => { 18 | const item = items[index]; 19 | return ( 20 | // biome-ignore lint/suspicious/noArrayIndexKey: array index is stable 21 | 22 | ); 23 | })} 24 | 25 | ); 26 | } 27 | 28 | const styles = StyleSheet.create({ 29 | container: { 30 | width: ENGRAMS_SECTION_WIDTH, 31 | marginLeft: DEFAULT_MARGIN, 32 | marginRight: DEFAULT_MARGIN, 33 | height: ENGRAMS_SECTION_HEIGHT, 34 | flexDirection: "row", 35 | flexWrap: "wrap", 36 | justifyContent: "space-between", 37 | alignContent: "space-between", 38 | alignSelf: "center", 39 | }, 40 | }); 41 | -------------------------------------------------------------------------------- /native/app/_authenticated/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { Stack } from "expo-router"; 2 | import { View, ActivityIndicator } from "react-native"; 3 | import { useGGStore } from "@/app/store/GGStore.ts"; 4 | 5 | export default function AuthenticatedLayout() { 6 | "use memo"; 7 | 8 | const appReady = useGGStore((state) => state.appReady); 9 | 10 | console.log("[AuthenticatedLayout] Rendering, appReady:", appReady); 11 | 12 | if (!appReady) { 13 | console.log("[AuthenticatedLayout] Showing loading - waiting for appReady"); 14 | return ( 15 | 16 | 17 | 18 | ); 19 | } 20 | 21 | console.log("[AuthenticatedLayout] Rendering Stack"); 22 | return ( 23 | 28 | 34 | 38 | 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /native/app/stats/Stats.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, View } from "react-native"; 2 | 3 | import type { DestinyItem } from "@/app/inventory/logic/Types.ts"; 4 | import { CategoryStyle, createSockets } from "@/app/inventory/logic/Sockets.ts"; 5 | import { createStats } from "@/app/stats/Logic.ts"; 6 | import ReusablePlugs from "@/app/stats/ReusablePlugs.tsx"; 7 | import StatBars from "@/app/stats/StatBars.tsx"; 8 | 9 | type Props = { 10 | readonly destinyItem: DestinyItem; 11 | }; 12 | 13 | export default function Stats({ destinyItem }: Props) { 14 | "use memo"; 15 | const sockets = createSockets(destinyItem); 16 | if (!sockets) { 17 | return null; 18 | } 19 | const stats = createStats(destinyItem, sockets); 20 | 21 | return ( 22 | 23 | {stats && } 24 | {sockets?.socketCategories 25 | .filter((category) => category.categoryStyle === CategoryStyle.Reusable) 26 | .map((category, _index) => ( 27 | 28 | ))} 29 | 30 | ); 31 | } 32 | 33 | const _styles = StyleSheet.create({ 34 | container: { 35 | flex: 1, 36 | backgroundColor: "#fff", 37 | alignItems: "center", 38 | justifyContent: "center", 39 | }, 40 | }); 41 | -------------------------------------------------------------------------------- /.github/workflows/autofix.yaml: -------------------------------------------------------------------------------- 1 | name: autofix.ci # needed to securely identify the workflow 2 | 3 | on: 4 | pull_request: 5 | branches: [main, "feature/*"] 6 | push: 7 | branches: [main, "feature/*"] 8 | workflow_dispatch: 9 | 10 | permissions: 11 | contents: read 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} 15 | cancel-in-progress: true 16 | 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 19 | TURBO_URL: ${{ secrets.TURBO_URL }} 20 | TURBO_CODE: ${{ secrets.TURBO_CODE }} 21 | 22 | jobs: 23 | format_fix: 24 | runs-on: macos-26 25 | timeout-minutes: 15 26 | steps: 27 | - uses: actions/checkout@v6.0.1 28 | - uses: pnpm/action-setup@v4.2.0 29 | with: 30 | version: 10.20.0 31 | - name: pnpm install 32 | run: pnpm install --frozen-lockfile 33 | - name: dedupe pnpm 34 | run: pnpm dedupe 35 | - name: format 36 | run: pnpm format:fix 37 | - name: lint 38 | run: pnpm lint:fix 39 | - name: pod install 40 | run: cd native/ios && pod install --repo-update 41 | 42 | - name: Suggest format changes 43 | uses: autofix-ci/action@v1.3.2 44 | 45 | -------------------------------------------------------------------------------- /native/app/App.tsx: -------------------------------------------------------------------------------- 1 | import { createNativeStackNavigator } from "@react-navigation/native-stack"; 2 | 3 | import MainDrawer from "@/app/UI/MainDrawer.tsx"; 4 | import Login from "@/app/UI/Login.tsx"; 5 | import DetailsView from "@/app/inventory/pages/details/DetailsView.tsx"; 6 | import type { RootStackParamList } from "@/app/Root.tsx"; 7 | 8 | const RootStack = createNativeStackNavigator(); 9 | 10 | function App() { 11 | "use memo"; 12 | 13 | return ( 14 | 15 | 16 | 23 | 34 | 35 | 36 | 37 | 38 | 39 | ); 40 | } 41 | 42 | export default App; 43 | -------------------------------------------------------------------------------- /native/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def reactNativeGradlePlugin = new File( 3 | providers.exec { 4 | workingDir(rootDir) 5 | commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })") 6 | }.standardOutput.asText.get().trim() 7 | ).getParentFile().absolutePath 8 | includeBuild(reactNativeGradlePlugin) 9 | 10 | def expoPluginsPath = new File( 11 | providers.exec { 12 | workingDir(rootDir) 13 | commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })") 14 | }.standardOutput.asText.get().trim(), 15 | "../android/expo-gradle-plugin" 16 | ).absolutePath 17 | includeBuild(expoPluginsPath) 18 | } 19 | 20 | plugins { 21 | id("com.facebook.react.settings") 22 | id("expo-autolinking-settings") 23 | } 24 | 25 | extensions.configure(com.facebook.react.ReactSettingsExtension) { ex -> 26 | if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') { 27 | ex.autolinkLibrariesFromCommand() 28 | } else { 29 | ex.autolinkLibrariesFromCommand(expoAutolinking.rnConfigCommand) 30 | } 31 | } 32 | expoAutolinking.useExpoModules() 33 | 34 | rootProject.name = 'Guardian Ghost' 35 | 36 | expoAutolinking.useExpoVersionCatalog() 37 | 38 | include ':app' 39 | includeBuild(expoAutolinking.reactNativeGradlePlugin) 40 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | # Run once a week so old code is regularly re-analyzed. 7 | schedule: 8 | - cron: '43 20 * * 2' 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | 14 | 15 | jobs: 16 | analyze-js-tsc: 17 | name: Analyze JS/TSC 18 | # Runner size impacts CodeQL analysis time. To learn more, please see: 19 | # - https://gh.io/recommended-hardware-resources-for-running-codeql 20 | # - https://gh.io/supported-runners-and-hardware-resources 21 | # - https://gh.io/using-larger-runners 22 | # Consider using larger runners for possible analysis time improvements. 23 | runs-on: 'ubuntu-latest' 24 | timeout-minutes: 5 25 | permissions: 26 | actions: read 27 | contents: read 28 | security-events: write 29 | 30 | steps: 31 | - name: Checkout repository 32 | uses: actions/checkout@v6.0.1 33 | 34 | # Initializes the CodeQL tools for scanning. 35 | - name: Initialize CodeQL 36 | uses: github/codeql-action/init@v4.31.7 37 | with: 38 | languages: 'javascript-typescript' 39 | 40 | - name: Autobuild 41 | uses: github/codeql-action/autobuild@v4.31.7 42 | 43 | - name: Perform CodeQL Analysis 44 | uses: github/codeql-action/analyze@v4.31.7 45 | with: 46 | category: "/language:javascript-typescript" 47 | -------------------------------------------------------------------------------- /patches/@gorhom__bottom-sheet.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/hooks/useBoundingClientRect.ts b/src/hooks/useBoundingClientRect.ts 2 | index cc85c8ced2de8ec514360368ed20af733f8f9aec..bdf117486a7d0d922266cd2bae15e633d40497b0 100644 3 | --- a/src/hooks/useBoundingClientRect.ts 4 | +++ b/src/hooks/useBoundingClientRect.ts 5 | @@ -56,17 +56,20 @@ export function useBoundingClientRect( 6 | } 7 | 8 | // @ts-ignore 👉 https://github.com/facebook/react/commit/53b1f69ba 9 | - if (ref.current.unstable_getBoundingClientRect !== null) { 10 | + const unstableGetBoundingClientRect = 11 | + ref.current.unstable_getBoundingClientRect; 12 | + if (typeof unstableGetBoundingClientRect === 'function') { 13 | // @ts-ignore https://github.com/facebook/react/commit/53b1f69ba 14 | - const layout = ref.current.unstable_getBoundingClientRect(); 15 | + const layout = unstableGetBoundingClientRect.call(ref.current); 16 | handler(layout); 17 | return; 18 | } 19 | 20 | // @ts-ignore once it `unstable_getBoundingClientRect` gets stable 🤞. 21 | - if (ref.current.getBoundingClientRect !== null) { 22 | + const getBoundingClientRect = ref.current.getBoundingClientRect; 23 | + if (typeof getBoundingClientRect === 'function') { 24 | // @ts-ignore once it `unstable_getBoundingClientRect` gets stable. 25 | - const layout = ref.current.getBoundingClientRect(); 26 | + const layout = getBoundingClientRect.call(ref.current); 27 | handler(layout); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json", 4 | "files": { 5 | "includes": [ 6 | "**", 7 | "!**/dist/**", 8 | "!**/ios/**", 9 | "!**/android/**", 10 | "!**/node_modules/**", 11 | "!**/.expo/**", 12 | "!**/app.json", 13 | "!**/eas.json", 14 | "!**/react-compiler-runtime/**", 15 | "!babel.config.js", 16 | "!**/minifier/index.ts", 17 | "!**/*.astro", 18 | "!**/minifier/**" 19 | ] 20 | }, 21 | "formatter": { 22 | "indentWidth": 2, 23 | "indentStyle": "space", 24 | "lineWidth": 120 25 | }, 26 | "linter": { 27 | "enabled": true, 28 | "rules": { 29 | "recommended": true, 30 | "style": { 31 | "noNonNullAssertion": "off", 32 | "noParameterAssign": "error", 33 | "useAsConstAssertion": "error", 34 | "useDefaultParameterLast": "error", 35 | "useEnumInitializers": "error", 36 | "useSelfClosingElements": "error", 37 | "useSingleVarDeclarator": "error", 38 | "noUnusedTemplateLiteral": "error", 39 | "useNumberNamespace": "error", 40 | "noInferrableTypes": "error", 41 | "noUselessElse": "error" 42 | }, 43 | "correctness": { 44 | "noUnusedImports": "error", 45 | "noUnusedVariables": "error", 46 | "useExhaustiveDependencies": "warn" 47 | }, 48 | "performance": { 49 | "recommended": true 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /native/ios/GuardianGhost/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryUserDefaults 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | CA92.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryFileTimestamp 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | 0A2A.1 21 | 3B52.1 22 | C617.1 23 | 24 | 25 | 26 | NSPrivacyAccessedAPIType 27 | NSPrivacyAccessedAPICategoryDiskSpace 28 | NSPrivacyAccessedAPITypeReasons 29 | 30 | E174.1 31 | 85F4.1 32 | 33 | 34 | 35 | NSPrivacyAccessedAPIType 36 | NSPrivacyAccessedAPICategorySystemBootTime 37 | NSPrivacyAccessedAPITypeReasons 38 | 39 | 35F9.1 40 | 41 | 42 | 43 | NSPrivacyCollectedDataTypes 44 | 45 | NSPrivacyTracking 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /native/images/svg/epic.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mono/docs/starlight/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "astro/config"; 2 | import starlight from "@astrojs/starlight"; 3 | 4 | // https://astro.build/config 5 | export default defineConfig({ 6 | site: "https://docs.guardianghost.com", 7 | integrations: [ 8 | starlight({ 9 | title: "GG Docs", 10 | social: [ 11 | { icon: "github", label: "GitHub", href: "https://github.com/NigelBreslaw/guardian-ghost" }, 12 | { icon: "email", label: "Email", href: "mailto:support@guardianghost.com" }, 13 | ], 14 | sidebar: [ 15 | { 16 | label: "Guides", 17 | items: [ 18 | { label: "Monorepo", link: "/guides/monorepo/" }, 19 | { label: "Coding Guidelines", link: "/guides/coding-guidelines/" }, 20 | { label: "Architecture", link: "/guides/architecture/" }, 21 | { label: "Infrastructure", link: "/guides/infrastructure/" }, 22 | { label: "Continuous Integration", link: "/guides/ci/" }, 23 | { label: "Automated Deployment", link: "/guides/automated-deployment/" }, 24 | { label: "Project Maintenance", link: "/guides/project-maintenance/" }, 25 | { label: "React Native", link: "/guides/react-native/" }, 26 | { label: "Costs", link: "/guides/costs/" }, 27 | { label: "Misc", link: "/guides/misc/" }, 28 | { label: "Authentication", link: "/guides/authentication/" }, 29 | { label: "To-do's", link: "/guides/todo/" }, 30 | ], 31 | }, 32 | ], 33 | }), 34 | ], 35 | }); 36 | -------------------------------------------------------------------------------- /mono/examples/default-project/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /native/app/inventory/UiRowRenderItem.tsx: -------------------------------------------------------------------------------- 1 | import { UISection, type UISections } from "@/app/inventory/logic/Helpers.ts"; 2 | import EngramsUI from "@/app/inventory/sections/EngramsUI.tsx"; 3 | import CharacterEquipmentUI from "@/app/inventory/sections/CharacterEquipmentUI.tsx"; 4 | import SeparatorUI from "@/app/inventory/sections/SeparatorUI.tsx"; 5 | import LostItemsUI from "@/app/inventory/sections/LostItemsUI.tsx"; 6 | import ArtifactUI from "@/app/inventory/sections/ArtifactUI.tsx"; 7 | import VaultSpacerUI from "@/app/inventory/sections/VaultSpacerUI.tsx"; 8 | import LootItemRow from "@/app/inventory/sections/LootItemRow.tsx"; 9 | import GuardianDetails from "@/app/inventory/sections/GuardianDetails.tsx"; 10 | 11 | type Props = { 12 | readonly item: UISections; 13 | }; 14 | 15 | export const UiCellRenderItem = ({ item }: Props) => { 16 | switch (item.type) { 17 | case UISection.Separator: 18 | return ; 19 | case UISection.CharacterEquipment: 20 | return ; 21 | case UISection.Engrams: 22 | return ; 23 | case UISection.LostItems: 24 | return ; 25 | case UISection.Artifact: 26 | return ; 27 | case UISection.VaultSpacer: 28 | return ; 29 | case UISection.LootRow: 30 | return ; 31 | case UISection.GuardianDetails: 32 | return ; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /native/components/ui/radio-group.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { View } from "react-native"; 3 | import * as RadioGroupPrimitive from "@rn-primitives/radio-group"; 4 | import { cn } from "@/lib/utils.ts"; 5 | 6 | const RadioGroup = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >(({ className, ...props }, ref) => { 10 | return ; 11 | }); 12 | RadioGroup.displayName = RadioGroupPrimitive.Root.displayName; 13 | const RadioGroupItem = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef 16 | >(({ className, ...props }, ref) => { 17 | return ( 18 | 27 | 28 | 29 | 30 | 31 | ); 32 | }); 33 | RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName; 34 | export { RadioGroup, RadioGroupItem }; 35 | -------------------------------------------------------------------------------- /native/android/app/src/main/java/com/guardianghost/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.guardianghost 2 | 3 | import android.app.Application 4 | import android.content.res.Configuration 5 | 6 | import com.facebook.react.PackageList 7 | import com.facebook.react.ReactApplication 8 | import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative 9 | import com.facebook.react.ReactPackage 10 | import com.facebook.react.ReactHost 11 | import com.facebook.react.common.ReleaseLevel 12 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint 13 | 14 | import expo.modules.ApplicationLifecycleDispatcher 15 | import expo.modules.ExpoReactHostFactory 16 | 17 | class MainApplication : Application(), ReactApplication { 18 | 19 | override val reactHost: ReactHost by lazy { 20 | ExpoReactHostFactory.getDefaultReactHost( 21 | context = applicationContext, 22 | packageList = 23 | PackageList(this).packages.apply { 24 | // Packages that cannot be autolinked yet can be added manually here, for example: 25 | // add(MyReactNativePackage()) 26 | } 27 | ) 28 | } 29 | 30 | override fun onCreate() { 31 | super.onCreate() 32 | DefaultNewArchitectureEntryPoint.releaseLevel = try { 33 | ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase()) 34 | } catch (e: IllegalArgumentException) { 35 | ReleaseLevel.STABLE 36 | } 37 | loadReactNative(this) 38 | ApplicationLifecycleDispatcher.onApplicationCreate(this) 39 | } 40 | 41 | override fun onConfigurationChanged(newConfig: Configuration) { 42 | super.onConfigurationChanged(newConfig) 43 | ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /.github/workflows/update-definitions.yml: -------------------------------------------------------------------------------- 1 | name: Update definitions 2 | 3 | # Run every 10 mins during Bungie's working hours. 4 | # The Action takes ~10 seconds to run if there is no new manifest. 5 | # Github give 2000 minutes (120_000 seconds) per month 6 | on: 7 | workflow_dispatch: 8 | schedule: 9 | - cron: "*/10 15-23 * * *" 10 | - cron: "*/10 0-2 * * *" 11 | 12 | jobs: 13 | deploy: 14 | runs-on: ubuntu-latest 15 | env: 16 | TURBO_URL: ${{ secrets.TURBO_URL }} 17 | TURBO_CODE: ${{ secrets.TURBO_CODE }} 18 | 19 | permissions: 20 | contents: read 21 | deployments: write 22 | name: Deploy 23 | steps: 24 | - uses: actions/checkout@v6.0.1 25 | - uses: oven-sh/setup-bun@v2 26 | - uses: actions/setup-node@v6.1.0 27 | with: 28 | node-version: '24' 29 | - name: bun install 30 | run: cd minifier && bun run next_gen.ts --check-manifest 31 | shell: bash {0} 32 | - name: copy json definitions 33 | run: cd minifier && mv json ../native/public 34 | - name: Install Wrangler 35 | run: npm install -g wrangler@3.90.0 36 | - name: deploy website 37 | env: 38 | CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} 39 | CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} 40 | run: wrangler pages deploy native/public --project-name=gg-app --commit-dirty=true 41 | - name: Send Slack Notification 42 | env: 43 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 44 | run: | 45 | curl -X POST -H 'Content-type: application/json' --data '{"text":"Guardian Ghost: New Destiny Item Definitions were just created"}' $SLACK_WEBHOOK_URL 46 | -------------------------------------------------------------------------------- /native/app/bungie/Account.ts: -------------------------------------------------------------------------------- 1 | import type { AuthToken } from "@/app/store/Authentication/Utilities.ts"; 2 | import { apiKey } from "@/constants/env.ts"; 3 | import type { BungieUser } from "../inventory/logic/Types.ts"; 4 | import type { BungieProfile } from "@/app/core/ApiResponse.ts"; 5 | 6 | export async function getLinkedProfiles(authToken: AuthToken, getAllAccounts = false): Promise { 7 | const headers = new Headers(); 8 | headers.append("Authorization", `Bearer ${authToken.access_token}`); 9 | headers.append("X-API-Key", apiKey); 10 | 11 | const parameters = "?getAllMemberships=true"; 12 | 13 | const requestOptions: RequestInit = { 14 | method: "GET", 15 | headers: headers, 16 | }; 17 | 18 | return new Promise((resolve, reject) => { 19 | fetch( 20 | `https://www.bungie.net/Platform/Destiny2/254/Profile/${authToken.membership_id}/LinkedProfiles/${ 21 | getAllAccounts ? parameters : "" 22 | }`, 23 | requestOptions, 24 | ) 25 | .then((response) => { 26 | if (!response.ok) { 27 | console.error(response); 28 | throw new Error(`HTTP error! Status: ${response.status}`); 29 | } 30 | return response.json(); 31 | }) 32 | .then((data) => { 33 | resolve(data); 34 | }) 35 | .catch((error) => { 36 | console.error("getRefreshToken", error); 37 | reject(new Error("Failed to get authToken")); 38 | }); 39 | }); 40 | } 41 | 42 | export function getBungieUser(bungieProfile: BungieProfile): BungieUser { 43 | return { 44 | profile: { 45 | membershipId: bungieProfile.membershipId, 46 | membershipType: bungieProfile.membershipType, 47 | displayName: bungieProfile.displayName, 48 | }, 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /.github/workflows/deploy-gg-web.yml: -------------------------------------------------------------------------------- 1 | name: deploy-gg-web-app 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | paths: 7 | - "native/ReleaseNotes/**" 8 | - "minifier/**" 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | deploy: 16 | runs-on: ubuntu-latest 17 | env: 18 | TURBO_URL: ${{ secrets.TURBO_URL }} 19 | TURBO_CODE: ${{ secrets.TURBO_CODE }} 20 | 21 | permissions: 22 | contents: read 23 | deployments: write 24 | name: Deploy 25 | steps: 26 | - uses: actions/checkout@v6.0.1 27 | - uses: oven-sh/setup-bun@v2 28 | - name: bun install 29 | run: cd minifier && bun start 30 | shell: bash {0} 31 | - name: copy json definitions 32 | run: cd minifier && mv json ../native/public 33 | # - uses: pnpm/action-setup@v4.1.0 34 | # with: 35 | # version: 10.20.0 36 | # - name: install dependencies 37 | # run: cd native && pnpm install --frozen-lockfile 38 | # - name: add .env file 39 | # run: cd native && echo '${{ secrets.CLIENT_SECRETS_WEB }}' > .env 40 | # - name: build # Plus workaround cloudflare not uploading the node_modules folder 41 | # run: | 42 | # cd native 43 | # pnpm expo export --source-maps --platform web 44 | # mv dist/assets/node_modules/* dist/assets/ 45 | # find dist/_expo/static/js/web/ -type f -print0 | xargs -0 sed -i 's/assets\/node_modules/assets/g' 46 | - name: deploy website 47 | uses: cloudflare/wrangler-action@v3.14.1 48 | with: 49 | apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} 50 | accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} 51 | command: pages deploy native/public --project-name=gg-app 52 | gitHubToken: ${{ secrets.GITHUB_TOKEN }} 53 | -------------------------------------------------------------------------------- /native/app/inventory/cells/EmptyCell.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, View } from "react-native"; 2 | 3 | import { ICON_SIZE } from "@/app/utilities/UISize.ts"; 4 | 5 | const BORDER_COLOR = "#555555"; 6 | const BORDER_RADIUS = 10; 7 | const BORDER_SIZE = 15; 8 | const BORDER_WIDTH = 1; 9 | 10 | export default function EmptyCell() { 11 | "use memo"; 12 | return ( 13 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | } 21 | 22 | const styles = StyleSheet.create({ 23 | square: { 24 | width: ICON_SIZE, 25 | height: ICON_SIZE, 26 | }, 27 | corner: { 28 | position: "absolute", 29 | width: BORDER_SIZE, 30 | height: BORDER_SIZE, 31 | borderColor: BORDER_COLOR, 32 | }, 33 | topLeft: { 34 | top: 0, 35 | left: 0, 36 | borderTopWidth: BORDER_WIDTH, 37 | borderLeftWidth: BORDER_WIDTH, 38 | borderTopLeftRadius: BORDER_RADIUS, 39 | }, 40 | topRight: { 41 | top: 0, 42 | right: 0, 43 | borderTopWidth: BORDER_WIDTH, 44 | borderRightWidth: BORDER_WIDTH, 45 | borderTopRightRadius: BORDER_RADIUS, 46 | }, 47 | bottomLeft: { 48 | bottom: 0, 49 | left: 0, 50 | borderBottomWidth: BORDER_WIDTH, 51 | borderLeftWidth: BORDER_WIDTH, 52 | borderBottomLeftRadius: BORDER_RADIUS, 53 | }, 54 | bottomRight: { 55 | bottom: 0, 56 | right: 0, 57 | borderBottomWidth: BORDER_WIDTH, 58 | borderRightWidth: BORDER_WIDTH, 59 | borderBottomRightRadius: BORDER_RADIUS, 60 | }, 61 | }); 62 | 63 | const topLeft = StyleSheet.flatten([styles.topLeft, styles.corner]); 64 | const topRight = StyleSheet.flatten([styles.topRight, styles.corner]); 65 | const bottomLeft = StyleSheet.flatten([styles.bottomLeft, styles.corner]); 66 | const bottomRight = StyleSheet.flatten([styles.bottomRight, styles.corner]); 67 | -------------------------------------------------------------------------------- /native/app/_authenticated/details/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { Stack, useRouter } from "expo-router"; 2 | import { Platform, Pressable } from "react-native"; 3 | import { ChevronLeft, ArrowLeft } from "lucide-react-native"; 4 | 5 | function BackButton() { 6 | "use memo"; 7 | const router = useRouter(); 8 | 9 | return ( 10 | router.back()} 12 | style={({ pressed }) => ({ 13 | opacity: pressed ? 0.5 : 1, 14 | flexDirection: "row", 15 | alignItems: "center", 16 | paddingLeft: Platform.OS === "ios" ? 0 : 16, 17 | paddingRight: 16, 18 | })} 19 | > 20 | {Platform.OS === "ios" ? : } 21 | 22 | ); 23 | } 24 | 25 | export default function DetailsLayout() { 26 | return ( 27 | , 40 | }), 41 | }} 42 | > 43 | , 54 | }), 55 | }} 56 | /> 57 | 58 | ); 59 | } 60 | -------------------------------------------------------------------------------- /native/ios/ci_scripts/ci_post_clone.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Ensure that the script fails if any error occurs. Otherwise Xcode Cloud will continue 4 | # any you might spend hours debugging the wrong part of the workflow. 5 | set -e 6 | set -x 7 | 8 | # Xcode cloud could x86 or arm64 architecture. So detect it and install node accordingly. 9 | # arch 10 | # node_version=20.15.0 11 | 12 | # if [ "$ARCHITECTURE" == "arm64" ]; then 13 | # # For arm64 architecture (Apple Silicon) 14 | # arch=arm64 15 | # else 16 | # # For x86 architecture 17 | # arch=x64 18 | # fi 19 | 20 | # # Echo for debugging logs purposes 21 | # echo $HOME 22 | # echo "============> Installing Node <============" 23 | 24 | # # Download and install node 25 | # curl "https://nodejs.org/dist/v$node_version/node-v$node_version-darwin-$arch.tar.gz" -o $HOME/Downloads/node.tar.gz 26 | # cd $CI_WORKSPACE_PATH 27 | # tar -xf "$HOME/Downloads/node.tar.gz" 28 | # NODE_PATH="$PWD/node-v$node_version-darwin-$arch/bin" 29 | # echo $NODE_PATH 30 | # PATH+=":$NODE_PATH" 31 | # export PATH 32 | 33 | # Install node. 34 | echo "============> Installing node <============" 35 | brew install node 36 | 37 | # Check node and npm version 38 | node -v 39 | npm -v 40 | 41 | # Install cocoapods. 42 | echo "============> Installing cocoapods <============" 43 | brew install cocoapods 44 | 45 | # Install pnpm 46 | npm install -g pnpm@10.20.0 47 | pnpm -v 48 | 49 | 50 | # move to the react native project. 51 | echo "=====> Moving to build directory" 52 | pwd 53 | cd $CI_PRIMARY_REPOSITORY_PATH/native 54 | pwd 55 | 56 | 57 | 58 | # Add the .env file 59 | echo "Adding .env file" 60 | echo $CLIENT_SECRETS > .env 61 | 62 | # Install npm dependencies. 63 | echo "=> Install npm dependencies" 64 | # Workaround for Xcode Cloud issue https://forums.developer.apple.com/forums/thread/738136 65 | pnpm install --frozen-lockfile 66 | 67 | 68 | # Install all pod dependencies. 69 | echo "=> Install pods" 70 | cd ios && pwd && pod install 71 | -------------------------------------------------------------------------------- /mono/docs/starlight/src/content/docs/guides/project-maintenance.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: CI info 3 | description: Details on how the CI was setup 4 | --- 5 | 6 | 7 | ### .github/workflows/main.yml 8 | 9 | import { FileTree } from '@astrojs/starlight/components'; 10 | 11 | 12 | 13 | - .github/ 14 | - workflows/ 15 | - **main.yml** 16 | - dependabot.yml 17 | 18 | 19 | 20 | The 'main.yml' github action is triggered on every push to the repo. See more here for how that works [Source helper](https://how.wtf/run-workflow-step-or-job-based-on-file-changes-github-actions.html). 21 | 22 | ### Dependabot 23 | 24 | Dependabot runs every workday in the morning. It checks for any dependency updates and creates a PR if it finds any. It also checks for any security vulnerabilities and creates a PR if it finds any. 25 | 26 | Updates are then manually reviewed and merged in the following order: 27 | 28 | 1. Security updates (Any change to Dependabot or CodeQL github-actions counts as a security update). 29 | 2. Breaking updates. 30 | 3. Non-breaking 'github-actions' updates. 31 | 4. Non-breaking 'dependency' updates. 32 | 5. Non-breaking 'devDependency' updates. 33 | 34 | If after merging a PR a Dependabot PR has a conflict, Dependabot will automatically update the PR with the latest changes and rebase it. This can take a few minutes. 35 | To see the progress of these updates they can be found [here](https://github.com/NigelBreslaw/guardian-ghost/network/updates). 36 | 37 | 38 | ### CI secrets 39 | 40 | Dependabot doesn't get access to repo secrets to be able to deploy the various web projects after a dependency changes. These secrets are duplicated [here](https://github.com/NigelBreslaw/guardian-ghost/settings/secrets/dependabot). 41 | 42 | 43 | ### Tokens and Certificates 44 | 45 | Most project certificates automatically renew themselves. However the cloudflare tokens to deploy need updating every 90 days. On a solo project like this it isn't really necessary, but just a good habit to keep. -------------------------------------------------------------------------------- /native/app/screens/Settings.tsx: -------------------------------------------------------------------------------- 1 | import { View } from "react-native"; 2 | import { Label } from "@/components/ui/label"; 3 | import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; 4 | import { cn } from "@/lib/utils.ts"; 5 | import { useGGStore } from "@/app/store/GGStore.ts"; 6 | import type { ShowBottomSheetStringValues } from "@/app/store/SettingsSlice.ts"; 7 | 8 | export default function Settings() { 9 | const showBottomSheetPreference = useGGStore((state) => state.showBottomSheetPreference); 10 | const setBottomSheetPreference = useGGStore((state) => state.setBottomSheetPreference); 11 | return ( 12 | 13 | 14 | 17 | 18 | 19 | 20 | 25 | 30 | 31 | 32 | ); 33 | } 34 | function RadioGroupItemWithLabel({ 35 | value, 36 | label, 37 | onLabelPress, 38 | }: { 39 | value: ShowBottomSheetStringValues; 40 | label: string; 41 | onLabelPress: (ShowBottomSheetPreference: string) => void; 42 | }) { 43 | return ( 44 | 45 | 46 | 49 | 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /native/android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 22 | 23 | 24 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /native/app/store/SettingsSlice.ts: -------------------------------------------------------------------------------- 1 | import type { IStore } from "@/app/store/GGStore.ts"; 2 | import type { StateCreator } from "zustand"; 3 | 4 | export type SettingsSliceSetter = Parameters>[0]; 5 | export type SettingsSliceGetter = Parameters>[1]; 6 | 7 | export enum ShowBottomSheetPreference { 8 | Auto = "AUTOMATIC", 9 | AlwaysShowing = "ALWAYS_SHOWING", 10 | AlwaysMinimized = "ALWAYS_MINIMIZED", 11 | } 12 | 13 | export type ShowBottomSheetStringValues = "AUTOMATIC" | "ALWAYS_SHOWING" | "ALWAYS_MINIMIZED"; 14 | 15 | export enum ShowBottomSheet { 16 | show = "show", 17 | minimize = "minimize", 18 | } 19 | 20 | export interface SettingsSlice { 21 | showBottomSheetPreference: ShowBottomSheetPreference; 22 | showNextBottomSheet: ShowBottomSheet; 23 | setBottomSheetPreference: (showBottomSheetPreference: string) => void; 24 | setShowBottomSheet: (showBottomSheet: ShowBottomSheet) => void; 25 | } 26 | 27 | export const createSettingsSlice: StateCreator = (set, get) => ({ 28 | showBottomSheetPreference: ShowBottomSheetPreference.Auto, 29 | showNextBottomSheet: ShowBottomSheet.show, 30 | setBottomSheetPreference: (showBottomSheetPreference: string) => { 31 | if (get().showBottomSheetPreference !== showBottomSheetPreference) { 32 | switch (showBottomSheetPreference) { 33 | case ShowBottomSheetPreference.Auto: 34 | set({ showBottomSheetPreference }); 35 | break; 36 | case ShowBottomSheetPreference.AlwaysShowing: 37 | set({ showBottomSheetPreference, showNextBottomSheet: ShowBottomSheet.show }); 38 | break; 39 | case ShowBottomSheetPreference.AlwaysMinimized: 40 | set({ showBottomSheetPreference, showNextBottomSheet: ShowBottomSheet.minimize }); 41 | break; 42 | } 43 | } 44 | }, 45 | setShowBottomSheet: (showBottomSheet: ShowBottomSheet) => { 46 | if (get().showBottomSheetPreference === ShowBottomSheetPreference.Auto) 47 | set({ showNextBottomSheet: showBottomSheet }); 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /native/app/core/generated/HelperKeys.ts: -------------------------------------------------------------------------------- 1 | // AUTO-GENERATED by minifier/next_gen.ts. Do not edit manually. 2 | 3 | export const HELPER_MAP = { 4 | Descriptions: { 5 | special: false, 6 | }, 7 | DisplaySources: { 8 | special: false, 9 | }, 10 | ExpirationTooltip: { 11 | special: false, 12 | }, 13 | ItemTypeDisplayName: { 14 | special: false, 15 | }, 16 | ExpiredInActivityMessage: { 17 | special: false, 18 | }, 19 | IconWaterMark: { 20 | special: false, 21 | }, 22 | IconWaterMarkFeatured: { 23 | special: false, 24 | }, 25 | TraitIds: { 26 | special: false, 27 | }, 28 | UiItemDisplayStyle: { 29 | special: false, 30 | }, 31 | PlugCategoryIdentifier: { 32 | special: false, 33 | }, 34 | UiPlugLabel: { 35 | special: false, 36 | }, 37 | InsertionMaterialRequirementHash: { 38 | special: false, 39 | }, 40 | StackUniqueLabel: { 41 | special: false, 42 | }, 43 | BucketTypeHash: { 44 | special: false, 45 | }, 46 | Versions: { 47 | special: false, 48 | }, 49 | StatHash: { 50 | special: false, 51 | }, 52 | StatGroupHash: { 53 | special: false, 54 | }, 55 | DamageTypeHashes: { 56 | special: false, 57 | }, 58 | ItemValue: { 59 | special: false, 60 | }, 61 | TooltipNotifications: { 62 | special: false, 63 | }, 64 | RandomizedPlugSetHash: { 65 | special: false, 66 | }, 67 | ReusablePlugSetHash: { 68 | special: false, 69 | }, 70 | SingleInitialItemHash: { 71 | special: false, 72 | }, 73 | SocketCategoryHash: { 74 | special: false, 75 | }, 76 | SocketIndexes: { 77 | special: true, 78 | }, 79 | SocketCategories: { 80 | special: true, 81 | }, 82 | PlugCategoryHash: { 83 | special: false, 84 | }, 85 | SocketEntries: { 86 | special: true, 87 | }, 88 | SocketTypeHash: { 89 | special: false, 90 | }, 91 | TalentGridHash: { 92 | special: false, 93 | }, 94 | Icons: { 95 | special: false, 96 | }, 97 | } as const; 98 | 99 | export type HelperKey = keyof typeof HELPER_MAP; 100 | -------------------------------------------------------------------------------- /native/app/inventory/pages/details/QuantityPicker.tsx: -------------------------------------------------------------------------------- 1 | import { View, TextInput, StyleSheet } from "react-native"; 2 | 3 | import Text from "@/app/UI/Text.tsx"; 4 | import type { DestinyItem } from "@/app/inventory/logic/Types.ts"; 5 | import { useGGStore } from "@/app/store/GGStore.ts"; 6 | 7 | type Props = { 8 | readonly destinyItem: DestinyItem; 9 | }; 10 | 11 | export default function QuantityPicker({ destinyItem }: Props) { 12 | "use memo"; 13 | const quantity = useGGStore((state) => state.quantityToTransfer); 14 | 15 | return ( 16 | 17 | {"Quantity to transfer:"} 18 | 19 | { 25 | const maxAmount = useGGStore.getState().findMaxQuantityToTransfer(destinyItem); 26 | const valueAsNumber = Number.parseInt(value, 10); 27 | if (valueAsNumber > maxAmount) { 28 | useGGStore.getState().setQuantityToTransfer(maxAmount); 29 | } else if (valueAsNumber < 1 || Number.isNaN(valueAsNumber)) { 30 | useGGStore.getState().setQuantityToTransfer(0); 31 | } else { 32 | useGGStore.getState().setQuantityToTransfer(valueAsNumber); 33 | } 34 | }} 35 | /> 36 | 37 | 38 | ); 39 | } 40 | 41 | const styles = StyleSheet.create({ 42 | quantityRoot: { 43 | left: 20, 44 | position: "absolute", 45 | bottom: 20, 46 | }, 47 | quantity: { 48 | width: 100, 49 | height: 30, 50 | borderRadius: 4, 51 | borderWidth: 2, 52 | borderColor: "grey", 53 | }, 54 | quantityText: { 55 | color: "white", 56 | fontSize: 15, 57 | fontWeight: "bold", 58 | includeFontPadding: false, 59 | height: "100%", 60 | width: "100%", 61 | paddingLeft: 5, 62 | }, 63 | quantityTitle: { 64 | color: "white", 65 | fontSize: 15, 66 | fontWeight: "bold", 67 | includeFontPadding: false, 68 | }, 69 | }); 70 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" 9 | directory: "/" # Location react native package.json 10 | open-pull-requests-limit: 20 11 | schedule: 12 | interval: "daily" 13 | time: "04:00" 14 | groups: 15 | expo: 16 | patterns: 17 | - "expo*" 18 | - "@expo*" 19 | - "expo-atlas" 20 | vitest: 21 | patterns: 22 | - "vitest*" 23 | - "@vitest*" 24 | react-native: 25 | patterns: 26 | - "@react-native*" 27 | react-navigation: 28 | patterns: 29 | - "@react-navigation*" 30 | react-compiler: 31 | patterns: 32 | - "eslint-plugin-react-compiler" 33 | - "babel-plugin-react-compiler" 34 | - "react-compiler-runtime" 35 | react-native-reusables: 36 | patterns: 37 | - "@rn-primitives*" 38 | - "nativewind" 39 | - "tailwindcss" 40 | - "tailwind-merge" 41 | babel: 42 | patterns: 43 | - "@babel*" 44 | react: 45 | patterns: 46 | - "react" 47 | - "react-dom" 48 | - "react-*" 49 | - "@types/react*" 50 | exclude-patterns: 51 | - "react-native*" 52 | - "@react-native*" 53 | astro: 54 | patterns: 55 | - "astro*" 56 | - "@astro*" 57 | - "sharp" 58 | solidjs: 59 | patterns: 60 | - "solid-js*" 61 | - "vite-plugin-solid" 62 | # Maintain dependencies for GitHub Actions 63 | - package-ecosystem: "github-actions" 64 | # Workflow files stored in the default location of `.github/workflows`. (You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.) 65 | directory: "/" 66 | schedule: 67 | interval: "daily" 68 | time: "04:00" 69 | -------------------------------------------------------------------------------- /native/app/inventory/cells/EngramCell.tsx: -------------------------------------------------------------------------------- 1 | import { useRouter } from "expo-router"; 2 | import { Image } from "expo-image"; 3 | import { StyleSheet, TouchableOpacity, View } from "react-native"; 4 | 5 | import Text from "@/app/UI/Text.tsx"; 6 | import { INNER_FRAME_SIZE, common } from "@/app/utilities/UISize.ts"; 7 | import { EMPTY_ENGRAM } from "@/app/utilities/Constants.ts"; 8 | import type { DestinyItem } from "@/app/inventory/logic/Types.ts"; 9 | 10 | type Props = { 11 | readonly destinyItem: DestinyItem | undefined; 12 | }; 13 | 14 | export default function EngramCell({ destinyItem }: Props) { 15 | "use memo"; 16 | 17 | const router = useRouter(); 18 | 19 | if (destinyItem === undefined) { 20 | return ( 21 | 22 | 23 | 24 | ); 25 | } 26 | 27 | const handlePress = () => { 28 | const itemIdentifier = { 29 | characterId: destinyItem.characterId, 30 | itemHash: destinyItem.itemHash, 31 | itemInstanceId: destinyItem.itemInstanceId, 32 | bucketHash: destinyItem.bucketHash, 33 | }; 34 | router.push(`/_authenticated/details/${encodeURIComponent(JSON.stringify(itemIdentifier))}`); 35 | }; 36 | 37 | return ( 38 | 39 | 40 | 46 | {destinyItem.instance.primaryStat > 0 && ( 47 | 48 | {destinyItem.instance.primaryStat} 49 | 50 | )} 51 | 52 | 53 | ); 54 | } 55 | 56 | const styles = StyleSheet.create({ 57 | frameSize: { 58 | width: INNER_FRAME_SIZE, 59 | height: INNER_FRAME_SIZE, 60 | pointerEvents: "none", 61 | }, 62 | primaryStat: { 63 | ...common.primaryStat, 64 | bottom: 0, 65 | right: -4, 66 | }, 67 | powerLevelText: { 68 | ...common.primaryStatText, 69 | }, 70 | }); 71 | -------------------------------------------------------------------------------- /mono/apps/site/src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import "../styles/main.css"; 3 | 4 | const heading = "Guardian Ghost"; 5 | const subheading = "The ultimate companion for your Destiny 2 grind"; 6 | const appIcon = "/images/app-icon.svg"; 7 | const appScreenshot = "/images/phone.webp"; 8 | // const footerImage = "/images/banners.svg"; 9 | const badges = [ 10 | { 11 | link: "https://apps.apple.com/app/guardian-ghost/id6475198290", 12 | image: "/images/app-store-badge.svg", 13 | }, 14 | { 15 | link: "https://play.google.com/store/apps/details?id=com.guardianghost", 16 | image: "/images/google-play-badge.png", 17 | }, 18 | ]; 19 | const authors = [ 20 | { 21 | name: "Nigel Breslaw", 22 | url: "https://unintuitive.com", 23 | }, 24 | ]; 25 | const pageTitle = "App Showcase"; 26 | const favicon = "/images/favicon.svg"; 27 | --- 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | {pageTitle} 36 | 37 | 38 |
39 |
40 |
41 | 42 |

{heading}

43 |

{subheading}

44 |
45 | {badges.map(badge => ( 46 |
47 | 48 | 49 | 50 |
51 | ))} 52 |
53 |

Made with ♥ by 54 | {authors.map((author, index) => ( 55 | 56 | {index > 0 ? (index === authors.length - 1 ? ' and ' : ', ') : ''} 57 | {author.name} 58 | 59 | ))} 60 |

61 |
62 |
63 | 64 |
65 |
66 | 70 |
71 | 72 | 73 | -------------------------------------------------------------------------------- /native/tailwind.config.js: -------------------------------------------------------------------------------- 1 | const { hairlineWidth } = require("nativewind/theme"); 2 | 3 | /** @type {import('tailwindcss').Config} */ 4 | module.exports = { 5 | darkMode: "class", 6 | content: ["./app/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}"], 7 | presets: [require("nativewind/preset")], 8 | theme: { 9 | extend: { 10 | colors: { 11 | border: "hsl(var(--border))", 12 | input: "hsl(var(--input))", 13 | ring: "hsl(var(--ring))", 14 | background: "hsl(var(--background))", 15 | foreground: "hsl(var(--foreground))", 16 | primary: { 17 | DEFAULT: "hsl(var(--primary))", 18 | foreground: "hsl(var(--primary-foreground))", 19 | }, 20 | secondary: { 21 | DEFAULT: "hsl(var(--secondary))", 22 | foreground: "hsl(var(--secondary-foreground))", 23 | }, 24 | destructive: { 25 | DEFAULT: "hsl(var(--destructive))", 26 | foreground: "hsl(var(--destructive-foreground))", 27 | }, 28 | muted: { 29 | DEFAULT: "hsl(var(--muted))", 30 | foreground: "hsl(var(--muted-foreground))", 31 | }, 32 | accent: { 33 | DEFAULT: "hsl(var(--accent))", 34 | foreground: "hsl(var(--accent-foreground))", 35 | }, 36 | popover: { 37 | DEFAULT: "hsl(var(--popover))", 38 | foreground: "hsl(var(--popover-foreground))", 39 | }, 40 | card: { 41 | DEFAULT: "hsl(var(--card))", 42 | foreground: "hsl(var(--card-foreground))", 43 | }, 44 | }, 45 | borderWidth: { 46 | hairline: hairlineWidth(), 47 | }, 48 | keyframes: { 49 | "accordion-down": { 50 | from: { height: "0" }, 51 | to: { height: "var(--radix-accordion-content-height)" }, 52 | }, 53 | "accordion-up": { 54 | from: { height: "var(--radix-accordion-content-height)" }, 55 | to: { height: "0" }, 56 | }, 57 | }, 58 | animation: { 59 | "accordion-down": "accordion-down 0.2s ease-out", 60 | "accordion-up": "accordion-up 0.2s ease-out", 61 | }, 62 | }, 63 | }, 64 | plugins: [require("tailwindcss-animate")], 65 | }; 66 | -------------------------------------------------------------------------------- /mono/docs/starlight/src/content/docs/guides/authentication.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Authentication 3 | description: Details about setting up authentication 4 | --- 5 | 6 | 7 | ## General 8 | 9 | Setting up Oauth for web and native apps is such a PITA it's worth documenting it all here. 10 | 11 | ## iOS 12 | 13 | First an 'associated url' is needed. This means when bungie.com redirect back to 'https://app.guardianghost.com/auth' the iOS app will have the callback details sent to it. 14 | 15 | First step is registering the site with Apple. This is done with a json file called 'apple-app-site-association' that needs to be in a folder called '.well-known' in the root of the website. This should then be deployed. Full instructions [here](https://developer.apple.com/documentation/xcode/supporting-associated-domains). 16 | 17 | Next is to add an 'Associated Domains' entitlement to the iOS project file. It can be found under 'Targets > native > Signing & Capabilities > +'. It then needs a single entry for the applink 'applinks:app.guardianghost.com'. 18 | 19 | ## Android 20 | 21 | Before any changes to the app can be made an assetlinks.json file needs to be deployed to the associated website. 22 | This ends up being deployed as https://app.guardianghost.com/.well-known/assetlinks.json. 23 | 24 | This file contains a fingerprint from the key used to sign the app. Google handle the signing of the production 25 | app. While a debug.keystore is used for local builds. Both fingerprints have been added for now, however the debug.keystore is published on the public git repo. For a real app this would not be a safe thing to do. But would require 26 | a special local build to be configured, a different url that would be used in the app and the call back and also another entry on bungie.net for this dev version. There is a TODO to fix this at a later date. 27 | 28 | Details on how to setup the assetlinks and verify them can be found [here](https://developer.android.com/training/app-links/verify-android-applinks). 29 | 30 | Details on how to update the AndroidManifest.xml are [here](https://developer.android.com/training/app-links/deep-linking). 31 | 32 | The AndroidManifest has been setup so only the following link is captured by the app 'https://app.guardianghost.com/auth'. 33 | ## Web -------------------------------------------------------------------------------- /mono/docs/starlight/src/content/docs/guides/react-native.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: React Native 3 | description: Details about the project setup 4 | --- 5 | 6 | 7 | ## General 8 | 9 | Prettier, eslint and jest have been removed from the package.json. This roughly halves the number of dependencies that were being installed. There were only a handful of React Native specific eslint rules so the loss might not be a big deal? Also need to see if vitest can be used to replace what jest was doing. 10 | 11 | Running `npx react-native doctor` can find issue in the dev environment. 12 | 13 | ## iOS 14 | 15 | MacOS: Ruby needed to be updated to 3.3.0. The following config also added to 16 | .zshrc 17 | source /opt/homebrew/opt/chruby/share/chruby/chruby.sh 18 | source /opt/homebrew/opt/chruby/share/chruby/auto.sh 19 | chruby ruby-3.3.0 20 | 21 | Ensure cocoapods is installed. 22 | 23 | If cloning from scratch or switching to a new git worktree the cocoapods need reinstalling before `pnpm start` will work. 24 | 25 | First cd in the ios folder and then `bundle install && bundle exec pod install` 26 | 27 | ## Android 28 | 29 | Java 17 was needed. [SdkMan](https://sdkman.io/) was used instead of brew. 30 | 31 | `curl -s "https://get.sdkman.io" | bash` 32 | 33 | `source "/Users/nigelb/.sdkman/bin/sdkman-init.sh"` 34 | 35 | `sdk install java 17.0.9` 36 | 37 | `sdk list java` 38 | 39 | `sdk install java 17.0.9-tem` 40 | 41 | `java -version` => 17.0.9 42 | 43 | Also ensure the Android SDK Command Line Tools are installed via the Android Studio SDK manager. 44 | 45 | After setting up Android Studio and an emulator the following is needed in .zshrc 46 | 47 | export ANDROID_HOME=$HOME/Library/Android/sdk 48 | export PATH=$PATH:$ANDROID_HOME/emulator 49 | export PATH=$PATH:$ANDROID_HOME/platform-tools 50 | 51 | Remember to `source ~/.zshrc` after, or open a new terminal. Without this `pnpm start` will fail to first launch the emulator and then fail to launch the react native app, even though it will install it successfully. 52 | 53 | NOTE: I didn't have time to root cause this, but after cloning from scratch the Android project was missing some dependencies. Maybe the original init did some magic? I fixed these manually by 54 | 55 | pnpm add -D @react-native-community/cli-platform-android @react-native/gradle-plugin 56 | -------------------------------------------------------------------------------- /native/app/store/UIDataSlice.ts: -------------------------------------------------------------------------------- 1 | import type { StateCreator } from "zustand"; 2 | 3 | import { SectionBuckets } from "@/app/bungie/Enums.ts"; 4 | import { equipSectionBuckets } from "@/app/inventory/logic/Helpers.ts"; 5 | import { ProfileDataHelpers } from "@/app/store/Definitions.ts"; 6 | import type { IStore } from "@/app/store/GGStore.ts"; 7 | import { 8 | ENGRAMS_SECTION_HEIGHT, 9 | EQUIP_SECTION_SIZE, 10 | FOOTER_HEIGHT, 11 | ICON_MARGIN, 12 | ICON_SIZE, 13 | } from "@/app/utilities/UISize.ts"; 14 | 15 | export type UIDataSliceSetter = Parameters>[0]; 16 | export type UIDataSliceGetter = Parameters>[1]; 17 | 18 | export interface UIDataSlice { 19 | maxLostItemsRows: number; 20 | setLostItemsRows: (maxLostItemsRows: number) => void; 21 | getVaultSpacerSize: (bucket: SectionBuckets) => number; 22 | } 23 | 24 | export const createUIDataSlice: StateCreator = (set, get) => ({ 25 | maxLostItemsRows: 0, 26 | setLostItemsRows: (maxLostItemsRows) => { 27 | set({ maxLostItemsRows }); 28 | }, 29 | getVaultSpacerSize: (bucket) => { 30 | return getVaultSpacerSize(get, bucket); 31 | }, 32 | }); 33 | 34 | function getVaultSpacerSize(get: UIDataSliceGetter, bucket: SectionBuckets): number { 35 | if (equipSectionBuckets.includes(bucket)) { 36 | return EQUIP_SECTION_SIZE + FOOTER_HEIGHT; 37 | } 38 | 39 | if (bucket === SectionBuckets.Engram) { 40 | return ENGRAMS_SECTION_HEIGHT; 41 | } 42 | 43 | if (bucket === SectionBuckets.LostItem) { 44 | const maxLostItemsRows = get().maxLostItemsRows; 45 | 46 | return ICON_SIZE * maxLostItemsRows + (maxLostItemsRows - 1) * ICON_MARGIN + FOOTER_HEIGHT; 47 | } 48 | 49 | if (bucket === SectionBuckets.Artifact) { 50 | return ICON_SIZE + ICON_MARGIN; 51 | } 52 | 53 | if (bucket === SectionBuckets.Consumables) { 54 | const totalConsumables = ProfileDataHelpers.consumables.length; 55 | const totalRows = Math.ceil(totalConsumables / 5); 56 | return (ICON_SIZE + ICON_MARGIN) * totalRows; 57 | } 58 | 59 | if (bucket === SectionBuckets.Mods) { 60 | const totalMods = ProfileDataHelpers.mods.length; 61 | const totalRows = Math.ceil(totalMods / 5); 62 | return (ICON_SIZE + ICON_MARGIN) * totalRows; 63 | } 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /native/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "Guardian Ghost", 4 | "slug": "native_gg", 5 | "scheme": "guardianghost", 6 | "icon": "./assets/images/icon.png", 7 | "userInterfaceStyle": "dark", 8 | "assetBundlePatterns": [ 9 | "**/*" 10 | ], 11 | "newArchEnabled": true, 12 | "ios": { 13 | "buildNumber": "478", 14 | "version": "1.3.0", 15 | "associatedDomains": [ 16 | "applinks:app.guardianghost.com" 17 | ], 18 | "bundleIdentifier": "com.guardianghost.mobile", 19 | "config": { 20 | "usesNonExemptEncryption": false 21 | }, 22 | "buildReactNativeFromSource": false 23 | }, 24 | "androidStatusBar": { 25 | "barStyle": "light-content" 26 | }, 27 | "android": { 28 | "package": "com.guardianghost", 29 | "backgroundColor": "#17101F", 30 | "intentFilters": [ 31 | { 32 | "action": "VIEW", 33 | "autoVerify": true, 34 | "data": [ 35 | { 36 | "scheme": "https", 37 | "host": "app.guardianghost.com", 38 | "pathPrefix": "/auth" 39 | } 40 | ], 41 | "category": [ 42 | "BROWSABLE", 43 | "DEFAULT" 44 | ] 45 | } 46 | ] 47 | }, 48 | "web": { 49 | "output": "single", 50 | "bundler": "metro", 51 | "favicon": "./assets/images/favicon.png" 52 | }, 53 | "extra": { 54 | "eas": { 55 | "projectId": "aa838362-0c4a-434d-b70b-d67f764a5d32" 56 | } 57 | }, 58 | "plugins": [ 59 | [ 60 | "expo-splash-screen", 61 | { 62 | "backgroundColor": "#17101F", 63 | "image": "./assets/images/splash_dark.png", 64 | "resizeMode": "contain", 65 | "imageWidth": 200 66 | } 67 | ], 68 | [ 69 | "expo-build-properties", 70 | { 71 | "android": { 72 | "compileSdkVersion": 36, 73 | "targetSdkVersion": 36, 74 | "buildToolsVersion": "35.0.0" 75 | } 76 | } 77 | ], 78 | "expo-sqlite", 79 | "expo-web-browser", 80 | [ 81 | "react-native-bottom-tabs", 82 | { 83 | "theme": "material3-expressive" 84 | } 85 | ], 86 | "expo-image", 87 | "expo-router" 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /native/app/inventory/sections/CharacterEquipmentUI.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, View } from "react-native"; 2 | 3 | import { 4 | DEFAULT_SECTION_4_WIDTH, 5 | FOOTER_HEIGHT, 6 | EQUIP_SECTION_HEIGHT, 7 | ICON_MARGIN, 8 | ICON_SIZE, 9 | } from "@/app/utilities/UISize.ts"; 10 | import type { EquipSection } from "@/app/inventory/logic/Helpers.ts"; 11 | import DestinyCell from "@/app/inventory/cells/DestinyCell.tsx"; 12 | 13 | type Props = { 14 | readonly equipSection: EquipSection; 15 | }; 16 | 17 | export default function CharacterEquipmentUI({ equipSection }: Props) { 18 | "use memo"; 19 | 20 | return ( 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | ); 41 | } 42 | 43 | const styles = StyleSheet.create({ 44 | root: { 45 | width: DEFAULT_SECTION_4_WIDTH, 46 | height: EQUIP_SECTION_HEIGHT + FOOTER_HEIGHT, 47 | alignSelf: "center", 48 | }, 49 | footer: { 50 | height: FOOTER_HEIGHT, 51 | }, 52 | container: { 53 | flex: 3, 54 | flexDirection: "row", 55 | flexWrap: "wrap", 56 | justifyContent: "center", 57 | alignItems: "center", 58 | }, 59 | equip: { 60 | width: ICON_SIZE + ICON_MARGIN, 61 | }, 62 | equipAndInventoryHolder: { 63 | flexDirection: "row", 64 | height: EQUIP_SECTION_HEIGHT, 65 | }, 66 | inventoryGrid: { 67 | flex: 3, 68 | flexDirection: "row", 69 | flexWrap: "wrap", 70 | justifyContent: "space-between", 71 | alignContent: "space-between", 72 | }, 73 | }); 74 | -------------------------------------------------------------------------------- /native/app/inventory/pages/InventoryPages.tsx: -------------------------------------------------------------------------------- 1 | import { createNativeBottomTabNavigator } from "@bottom-tabs/react-navigation"; 2 | import { Platform, View } from "react-native"; 3 | import WeaponsPage from "@/app/inventory/pages/WeaponsPage.tsx"; 4 | import ArmorPage from "@/app/inventory/pages/ArmorPage.tsx"; 5 | import GeneralPage from "@/app/inventory/pages/GeneralPage.tsx"; 6 | import { InventoryPageEnums } from "@/app/inventory/logic/Helpers.ts"; 7 | import { useGGStore } from "@/app/store/GGStore.ts"; 8 | import OptionsMenu from "@/components/ui/OptionsMenu.tsx"; 9 | 10 | function pageEnumToPageName(pageEnum: InventoryPageEnums): string { 11 | switch (pageEnum) { 12 | case InventoryPageEnums.Armor: 13 | return "tab-armor"; 14 | case InventoryPageEnums.General: 15 | return "tab-inventory"; 16 | case InventoryPageEnums.Weapons: 17 | return "tab-weapons"; 18 | } 19 | return "tab-weapons"; 20 | } 21 | 22 | const Tab = createNativeBottomTabNavigator(); 23 | 24 | export default function InventoryPages() { 25 | "use memo"; 26 | 27 | return ( 28 | 29 | {Platform.OS !== "ios" && } 30 | 39 | require("../../../images/sword.svg"), 45 | lazy: false, 46 | }} 47 | /> 48 | require("../../../images/shield.svg"), 54 | lazy: false, 55 | }} 56 | /> 57 | require("../../../images/package.svg"), 63 | lazy: false, 64 | }} 65 | /> 66 | 67 | 68 | ); 69 | } 70 | -------------------------------------------------------------------------------- /native/app/store/GGStore.ts: -------------------------------------------------------------------------------- 1 | import { create } from "zustand"; 2 | import { subscribeWithSelector, persist, createJSONStorage } from "zustand/middleware"; 3 | import { AsyncStorage } from "expo-sqlite/kv-store"; 4 | 5 | import { type AccountSlice, createAccountSlice } from "./Account/AccountSlice.ts"; 6 | import { type AuthenticationSlice, createAuthenticationSlice } from "./Authentication/AuthenticationSlice.ts"; 7 | import { type DefinitionsSlice, createDefinitionsSlice } from "./DefinitionsSlice.ts"; 8 | import { type UIDataSlice, createUIDataSlice } from "./UIDataSlice.ts"; 9 | import { type SettingsSlice, createSettingsSlice } from "./SettingsSlice.ts"; 10 | 11 | export interface IStore extends AccountSlice, AuthenticationSlice, DefinitionsSlice, UIDataSlice, SettingsSlice {} 12 | 13 | export const useGGStore = create()( 14 | persist( 15 | subscribeWithSelector((...a) => ({ 16 | ...createAccountSlice(...a), 17 | ...createAuthenticationSlice(...a), 18 | ...createDefinitionsSlice(...a), 19 | ...createUIDataSlice(...a), 20 | ...createSettingsSlice(...a), 21 | })), 22 | { 23 | name: "gg-storage", 24 | storage: createJSONStorage(() => AsyncStorage), 25 | partialize: (state) => ({ 26 | currentListIndex: state.currentListIndex, 27 | currentInventoryPage: state.currentInventoryPage, 28 | weaponsPageOffsetY: state.weaponsPageOffsetY, 29 | armorPageOffsetY: state.armorPageOffsetY, 30 | generalPageOffsetY: state.generalPageOffsetY, 31 | weaponsSort: state.weaponsSort, 32 | armorSort: state.armorSort, 33 | showBottomSheetPreference: state.showBottomSheetPreference, 34 | showNextBottomSheet: state.showNextBottomSheet, 35 | 36 | itemDefinitionVersion: state.itemDefinitionVersion, 37 | bungieDefinitionVersions: state.bungieDefinitionVersions, 38 | previousDefinitionsSuccessfullyLoaded: state.previousDefinitionsSuccessfullyLoaded, 39 | }), 40 | onRehydrateStorage: () => { 41 | return (state, error) => { 42 | if (error) { 43 | console.error("an error happened during hydration", error); 44 | useGGStore.getState().showSnackBar("Failed to hydrate storage"); 45 | } else { 46 | if (state) { 47 | state.setStateHydrated(); 48 | } 49 | } 50 | }; 51 | }, 52 | }, 53 | ), 54 | ); 55 | -------------------------------------------------------------------------------- /native/ios/GuardianGhost/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Expo 2 | import React 3 | import ReactAppDependencyProvider 4 | 5 | @UIApplicationMain 6 | public class AppDelegate: ExpoAppDelegate { 7 | var window: UIWindow? 8 | 9 | var reactNativeDelegate: ExpoReactNativeFactoryDelegate? 10 | var reactNativeFactory: RCTReactNativeFactory? 11 | 12 | public override func application( 13 | _ application: UIApplication, 14 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil 15 | ) -> Bool { 16 | let delegate = ReactNativeDelegate() 17 | let factory = ExpoReactNativeFactory(delegate: delegate) 18 | delegate.dependencyProvider = RCTAppDependencyProvider() 19 | 20 | reactNativeDelegate = delegate 21 | reactNativeFactory = factory 22 | 23 | #if os(iOS) || os(tvOS) 24 | window = UIWindow(frame: UIScreen.main.bounds) 25 | factory.startReactNative( 26 | withModuleName: "main", 27 | in: window, 28 | launchOptions: launchOptions) 29 | #endif 30 | 31 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 32 | } 33 | 34 | // Linking API 35 | public override func application( 36 | _ app: UIApplication, 37 | open url: URL, 38 | options: [UIApplication.OpenURLOptionsKey: Any] = [:] 39 | ) -> Bool { 40 | return super.application(app, open: url, options: options) || RCTLinkingManager.application(app, open: url, options: options) 41 | } 42 | 43 | // Universal Links 44 | public override func application( 45 | _ application: UIApplication, 46 | continue userActivity: NSUserActivity, 47 | restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void 48 | ) -> Bool { 49 | let result = RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler) 50 | return super.application(application, continue: userActivity, restorationHandler: restorationHandler) || result 51 | } 52 | } 53 | 54 | class ReactNativeDelegate: ExpoReactNativeFactoryDelegate { 55 | // Extension point for config-plugins 56 | 57 | override func sourceURL(for bridge: RCTBridge) -> URL? { 58 | // needed to return the correct URL for expo-dev-client. 59 | bridge.bundleURL ?? bundleURL() 60 | } 61 | 62 | override func bundleURL() -> URL? { 63 | #if DEBUG 64 | return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: ".expo/.virtual-metro-entry") 65 | #else 66 | return Bundle.main.url(forResource: "main", withExtension: "jsbundle") 67 | #endif 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /native/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /mono/docs/starlight/src/content/docs/guides/monorepo.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Getting Started 3 | description: Details about the project Monorepo 4 | --- 5 | 6 | import { FileTree } from '@astrojs/starlight/components'; 7 | 8 | 9 | ## Guardian Ghost is setup as a monorepo. 10 | 11 | 12 | 13 | - .github/ 14 | - .vscode/ 15 | - mono/ 16 | - docs/ 17 | - starlight/ 18 | - examples/ 19 | - default-project/ 20 | - native/ 21 | 22 | 23 | 24 | Guardian Ghost is going to target Web, iOS and Android. With MacOS and Windows being a possibility in the future. To minimise 25 | developement effort this is all done inside a monorepo. Right now (Jan 2024) it isn't as integrated a monorepo as possible. 26 | This is due to React Native 0.73 not playing nicely with pnpm workspaces. However it looks like this will be fixed during 27 | 2024 and allow the structure of the monorepo to be simplified. 28 | 29 | 30 | ## Developer Environment 31 | 32 | Right now the project is only tested on MacOS, but should work as is on Linux and Windows. However the React Native project 33 | requries a Mac for iOS development. The Android side of the project should be fine on all platforms. 34 | 35 | ### Prerequisites 36 | 37 | Brew - MacOS Package manager.\ 38 | pnpm - Web Package manager.\ 39 | nvm - Node Version Manager.\ 40 | Visual Studio Code - IDE. Other IDEs are fine, but this is what the project is setup for and if you are a VIM nerd you can probably work 41 | out how to set everything up yourself.\ 42 | Android Studio - Compiling Android project.\ 43 | Xcode (plus command line tools) - Compiling iOS project.\ 44 | React.\ 45 | React Native (with Expo).\ 46 | Solid.JS.\ 47 | Astro.\ 48 | Typescript. 49 | 50 | ### setup 51 | 52 | To use the correct version of Node run `nvm use` inside the project. NVM picks up the correct version from the .nvmrc file in the root. 53 | 54 | The following setup presumes you are using Git Worktree. If that is new to you check out this quick [video](https://www.youtube.com/watch?v=2uEqYw-N8uE). 55 | 56 | First bare clone the repo `git clone --bare git@github.com:NigelBreslaw/guardian-ghost.git`. 57 | 58 | Then cd in `cd guardian-ghost.git` and setup the origin `git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"` or git fetch won't work as expected. 59 | 60 | When pushing a new branch you will see 'current branch has no upstream branch, blah blah blah'. As of git 2.37.0 and higher you can setup auto tracking and never have to deal with this again! `git config --global push.autoSetupRemote true` 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /native/app/index.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useRouter, Redirect } from "expo-router"; 3 | import { useGGStore } from "@/app/store/GGStore.ts"; 4 | import * as SplashScreen from "expo-splash-screen"; 5 | 6 | export default function Index() { 7 | "use memo"; 8 | const router = useRouter(); 9 | const authenticated = useGGStore((state) => state.authenticated); 10 | const stateHydrated = useGGStore((state) => state.stateHydrated); 11 | 12 | // Debug logging 13 | useEffect(() => { 14 | console.log("[Index] State:", { 15 | stateHydrated, 16 | authenticated, 17 | }); 18 | }, [stateHydrated, authenticated]); 19 | 20 | useEffect(() => { 21 | console.log("[Index] useEffect triggered:", { 22 | stateHydrated, 23 | authenticated, 24 | }); 25 | 26 | if (!stateHydrated) { 27 | console.log("[Index] Waiting for stateHydrated..."); 28 | return; 29 | } 30 | 31 | // Redirect based on authentication state 32 | if (authenticated === "NO-AUTHENTICATION") { 33 | console.log("[Index] Redirecting to /sign-in"); 34 | SplashScreen.hideAsync().catch(() => { 35 | // Ignore errors 36 | }); 37 | router.replace("/sign-in"); 38 | } else if (authenticated === "AUTHENTICATED") { 39 | console.log("[Index] Redirecting to /_authenticated/(tabs)/weapons"); 40 | SplashScreen.hideAsync().catch(() => { 41 | // Ignore errors 42 | }); 43 | router.replace("/_authenticated/(tabs)/weapons"); 44 | } else { 45 | console.log("[Index] Still initializing, authenticated state:", authenticated); 46 | } 47 | // If still INITIALIZING, wait - initAuthentication is still running 48 | }, [authenticated, stateHydrated, router]); 49 | 50 | // Show redirect component while waiting 51 | console.log("[Index] Rendering, stateHydrated:", stateHydrated, "authenticated:", authenticated); 52 | 53 | if (!stateHydrated) { 54 | console.log("[Index] Returning null - waiting for hydration"); 55 | return null; 56 | } 57 | 58 | if (authenticated === "NO-AUTHENTICATION") { 59 | console.log("[Index] Rendering Redirect to /sign-in"); 60 | return ; 61 | } 62 | 63 | if (authenticated === "AUTHENTICATED") { 64 | console.log("[Index] Rendering Redirect to /_authenticated/(tabs)/weapons"); 65 | return ; 66 | } 67 | 68 | // Still initializing - don't render anything 69 | console.log("[Index] Returning null - still initializing"); 70 | return null; 71 | } 72 | -------------------------------------------------------------------------------- /mono/docs/starlight/README.md: -------------------------------------------------------------------------------- 1 | # Starlight Starter Kit: Basics 2 | 3 | [![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build) 4 | 5 | ``` 6 | npm create astro@latest -- --template starlight 7 | ``` 8 | 9 | [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/starlight/tree/main/examples/basics) 10 | [![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/basics) 11 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fwithastro%2Fstarlight%2Ftree%2Fmain%2Fexamples%2Fbasics&project-name=my-starlight-docs&repository-name=my-starlight-docs) 12 | 13 | > 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! 14 | 15 | ## 🚀 Project Structure 16 | 17 | Inside of your Astro + Starlight project, you'll see the following folders and files: 18 | 19 | ``` 20 | . 21 | ├── public/ 22 | ├── src/ 23 | │ ├── assets/ 24 | │ ├── content/ 25 | │ │ ├── docs/ 26 | │ │ └── config.ts 27 | │ └── env.d.ts 28 | ├── astro.config.mjs 29 | ├── package.json 30 | └── tsconfig.json 31 | ``` 32 | 33 | Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name. 34 | 35 | Images can be added to `src/assets/` and embedded in Markdown with a relative link. 36 | 37 | Static assets, like favicons, can be placed in the `public/` directory. 38 | 39 | ## 🧞 Commands 40 | 41 | All commands are run from the root of the project, from a terminal: 42 | 43 | | Command | Action | 44 | | :------------------------ | :----------------------------------------------- | 45 | | `npm install` | Installs dependencies | 46 | | `npm run dev` | Starts local dev server at `localhost:4321` | 47 | | `npm run build` | Build your production site to `./dist/` | 48 | | `npm run preview` | Preview your build locally, before deploying | 49 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | 50 | | `npm run astro -- --help` | Get help using the Astro CLI | 51 | 52 | ## 👀 Want to learn more? 53 | 54 | Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat). 55 | -------------------------------------------------------------------------------- /mono/apps/site/README.md: -------------------------------------------------------------------------------- 1 | # Mobile App Showcase Astro Theme 2 | pb-rounded 3 | 4 | This theme is a fully responsive and customizable landing page for showcasing mobile apps. Built with Astro, it utilizes simple HTML and CSS for design and layout, ensuring simplicity and speed. Ideal for developers and designers looking for a lightweight starting point to promote their app. 5 | 6 | ## Features 7 | 8 | - **No Dependencies**: Apart from Astro, this theme does not use any external dependencies. 9 | - **Fully Customizable**: Customize every element of the theme including fonts, images, and text by simple edits. 10 | - **Responsive Design**: Ensures your app looks stunning on both desktop and mobile devices. 11 | 12 | ## Usage 13 | 14 | To begin using this theme for your mobile app landing page, we recommend taking advantage of the GitHub "Use this template" feature, located above the Clone button. This will allow you to create a separate repository where you can customize the theme as you wish. 15 | 16 | ## Getting Started 17 | 18 | 1. Create a new repository by clicking "Use this template". 19 | 2. Navigate to the project directory and install dependencies with `npm install`. 20 | 3. Start the development server with `npm start`. 21 | 22 | ## Customization Guide 23 | 24 | ### Content 25 | 26 | Edit the frontmatter section at the top of `/src/pages/index.html` to update the website content, including text and images. 27 | 28 | ### Styles 29 | 30 | All CSS is located in `/src/styles/main.css`. Modify this file to change the look and feel of the site. 31 | 32 | ### Images 33 | 34 | Replace images by uploading new ones to the `/public/images` folder and update the references in the frontmatter of `index.html`. 35 | 36 | ### Fonts 37 | 38 | Add new font files to `/public/fonts` and reference them in `/src/styles/main.css` to change fonts. For easy integration of Google Fonts into your project, check out [Hermes](https://github.com/cadensstudio/hermes). 39 | 40 | ## Project Structure 41 | 42 | - `/src/pages/index.html`: The main HTML file for your landing page. 43 | - `/src/styles/main.css`: CSS file for styling your landing page. 44 | - `/public/images`: Directory for storing images. 45 | - `/public/fonts`: Directory for storing fonts. 46 | 47 | ## Deployment 48 | 49 | This theme can be deployed on any static site hosting service that supports Astro. Follow the hosting provider's instructions for deploying an Astro project. 50 | 51 | To view a live version of this site, see https://partybanner.app. 52 | -------------------------------------------------------------------------------- /mono/apps/site/src/styles/main.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | :root { 4 | --accent: #FF9305; 5 | --secondary: #8e8e93; 6 | } 7 | 8 | * { 9 | box-sizing: border-box; 10 | margin: 0; 11 | } 12 | 13 | html { 14 | overflow-x: hidden; 15 | } 16 | 17 | body { 18 | font-family: -apple-system, BlinkMacSystemFont, Avenir Next, Segoe UI, Roboto, Noto Sans, Helvetica Neue, sans-serif; 19 | -webkit-font-smoothing: antialiased; 20 | color: var(--secondary); 21 | } 22 | 23 | h1, h2, h3 { 24 | line-height: 1.2; 25 | } 26 | 27 | h1 { 28 | font-size: 5em; 29 | font-weight: 900; 30 | margin-bottom: .1em; 31 | } 32 | 33 | h2 { 34 | font-size: 2em; 35 | font-weight: 400; 36 | } 37 | 38 | .container { 39 | display: flex; 40 | flex-direction: column; 41 | align-items: center; 42 | justify-content: space-between; 43 | min-height: 100vh; 44 | padding: 0; 45 | } 46 | 47 | main { 48 | margin: auto 0; 49 | padding-top: 30px; 50 | display: flex; 51 | justify-content: center; 52 | align-items: center; 53 | gap: 80px; 54 | } 55 | 56 | .text-container { 57 | width: 60%; 58 | } 59 | 60 | .app-icon { 61 | width: 80px; 62 | box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.1); 63 | border-radius: 24px; 64 | margin-bottom: 10px; 65 | } 66 | 67 | .heading { 68 | font-family: 'Helvetica', sans-serif; 69 | font-weight: 900; 70 | color: var(--accent); 71 | margin-bottom: 16px; 72 | letter-spacing: -2px; 73 | } 74 | 75 | .subheading { 76 | font-size: 1.75rem; 77 | font-weight: 300; 78 | margin-bottom: 30px; 79 | } 80 | 81 | .badge-container { 82 | display: flex; 83 | flex-wrap: wrap; 84 | gap: 16px; 85 | } 86 | 87 | .badge { 88 | margin-bottom: 20px; 89 | height: 50px; 90 | } 91 | .badge:hover { 92 | cursor: pointer; 93 | } 94 | 95 | .authors { 96 | font-weight: 300; 97 | } 98 | 99 | .authors a { 100 | color: inherit; 101 | font-weight: 500; 102 | text-decoration: none; 103 | } 104 | .authors a:hover { 105 | text-decoration: underline; 106 | } 107 | 108 | .app-screenshot { 109 | width: 400px; 110 | } 111 | 112 | footer { 113 | width: 100%; 114 | text-align: center; 115 | padding-top: 30px; 116 | overflow: hidden; 117 | } 118 | 119 | .footer-image { 120 | width: 100%; 121 | height: auto; 122 | margin: 0; 123 | padding: 0; 124 | position: relative; 125 | top: 30px; 126 | } 127 | 128 | @media (max-width: 768px) { 129 | main { 130 | flex-direction: column; 131 | padding: 40px; 132 | } 133 | .text-container { 134 | width: 100%; 135 | } 136 | .footer-image { 137 | top: 5px; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /native/ios/Podfile: -------------------------------------------------------------------------------- 1 | require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking") 2 | require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods") 3 | 4 | require 'json' 5 | podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {} 6 | 7 | def ccache_enabled?(podfile_properties) 8 | # Environment variable takes precedence 9 | return ENV['USE_CCACHE'] == '1' if ENV['USE_CCACHE'] 10 | 11 | # Fall back to Podfile properties 12 | podfile_properties['apple.ccacheEnabled'] == 'true' 13 | end 14 | 15 | ENV['RCT_NEW_ARCH_ENABLED'] ||= '0' if podfile_properties['newArchEnabled'] == 'false' 16 | ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] 17 | ENV['RCT_USE_RN_DEP'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false' 18 | ENV['RCT_USE_PREBUILT_RNCORE'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false' 19 | platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1' 20 | 21 | prepare_react_native_project! 22 | 23 | target 'GuardianGhost' do 24 | use_expo_modules! 25 | 26 | if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1' 27 | config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"]; 28 | else 29 | config_command = [ 30 | 'npx', 31 | 'expo-modules-autolinking', 32 | 'react-native-config', 33 | '--json', 34 | '--platform', 35 | 'ios' 36 | ] 37 | end 38 | 39 | config = use_native_modules!(config_command) 40 | 41 | use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks'] 42 | use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS'] 43 | 44 | use_react_native!( 45 | :path => config[:reactNativePath], 46 | :hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes', 47 | # An absolute path to your application root. 48 | :app_path => "#{Pod::Config.instance.installation_root}/..", 49 | :privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false', 50 | ) 51 | 52 | post_install do |installer| 53 | react_native_post_install( 54 | installer, 55 | config[:reactNativePath], 56 | :mac_catalyst_enabled => false, 57 | :ccache_enabled => ccache_enabled?(podfile_properties), 58 | ) 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /native/app/inventory/sections/LostItemsUI.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, View } from "react-native"; 2 | 3 | import { DEFAULT_MARGIN, FOOTER_HEIGHT, ICON_MARGIN, ICON_SIZE, INV_MAX_WIDTH } from "@/app/utilities/UISize.ts"; 4 | import { useGGStore } from "@/app/store/GGStore.ts"; 5 | import type { DestinyItem } from "@/app/inventory/logic/Types.ts"; 6 | import DestinyCell from "@/app/inventory/cells/DestinyCell.tsx"; 7 | import EmptyCell from "@/app/inventory/cells/EmptyCell.tsx"; 8 | import EngramCell from "@/app/inventory/cells/EngramCell.tsx"; 9 | import { ItemType } from "@/app/bungie/Enums.ts"; 10 | 11 | type Props = { 12 | readonly items: DestinyItem[]; 13 | }; 14 | 15 | export default function LostItemsUI({ items: destinyItems }: Props) { 16 | "use memo"; 17 | const maxLostItemsRows = useGGStore.getState().maxLostItemsRows; 18 | const minimumSpacerHeight = ICON_SIZE * maxLostItemsRows + ICON_MARGIN * (maxLostItemsRows - 1); 19 | 20 | const normalHeight = ICON_SIZE * maxLostItemsRows + ICON_MARGIN * (maxLostItemsRows - 1); 21 | 22 | const styles = StyleSheet.create({ 23 | root: { 24 | height: minimumSpacerHeight, 25 | }, 26 | container: { 27 | maxHeight: normalHeight, 28 | marginLeft: DEFAULT_MARGIN, 29 | marginRight: DEFAULT_MARGIN, 30 | maxWidth: INV_MAX_WIDTH, 31 | flex: 5, 32 | flexDirection: "row", 33 | flexWrap: "wrap", 34 | justifyContent: "space-between", 35 | alignContent: "space-between", 36 | }, 37 | footer: { 38 | height: FOOTER_HEIGHT, 39 | }, 40 | }); 41 | const totalItems = Array.from({ length: 5 * maxLostItemsRows }); 42 | 43 | return ( 44 | 45 | 46 | 47 | {totalItems.map((_v, index) => { 48 | const item = destinyItems[index]; 49 | if (item) { 50 | if (item.def.itemType === ItemType.Engram) { 51 | return ( 52 | // biome-ignore lint/suspicious/noArrayIndexKey: 53 | 54 | ); 55 | } 56 | return ( 57 | // biome-ignore lint/suspicious/noArrayIndexKey: array index is stable 58 | 59 | ); 60 | } 61 | return ( 62 | // biome-ignore lint/suspicious/noArrayIndexKey: array index is stable 63 | 64 | ); 65 | })} 66 | 67 | 68 | 69 | 70 | ); 71 | } 72 | -------------------------------------------------------------------------------- /native/app/UI/Spinner.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect } from "react"; 2 | import { View } from "react-native"; 3 | import Animated, { 4 | Easing, 5 | useAnimatedProps, 6 | useAnimatedStyle, 7 | useSharedValue, 8 | withRepeat, 9 | withSequence, 10 | withTiming, 11 | } from "react-native-reanimated"; 12 | import Svg, { Circle, G } from "react-native-svg"; 13 | 14 | type Props = { 15 | readonly color?: string; 16 | readonly size?: number; 17 | }; 18 | 19 | export default function Spinner({ color, size }: Props) { 20 | "use memo"; 21 | const AnimatedCircle = Animated.createAnimatedComponent(Circle); 22 | const CIRCUMFERENCE = size ?? 50; 23 | const R = CIRCUMFERENCE / (2 * Math.PI); 24 | const STROKE_WIDTH = 3; 25 | const HALF_CIRCLE = R + STROKE_WIDTH; 26 | const DIAMETER = 2 * HALF_CIRCLE; 27 | 28 | const progress = useSharedValue(0); 29 | const rotation = useSharedValue(0); 30 | 31 | const startAnimation = useCallback(() => { 32 | progress.value = withTiming(0.6, { duration: 1000 }); 33 | 34 | progress.value = withRepeat( 35 | withSequence(withTiming(0.7, { duration: 800 }), withTiming(0.1, { duration: 2000 })), 36 | -1, 37 | true, 38 | ); 39 | 40 | rotation.value = withRepeat(withTiming(360, { duration: 900, easing: Easing.linear }), -1, false); 41 | }, [progress, rotation]); 42 | 43 | const animatedCircleProps = useAnimatedProps(() => { 44 | return { 45 | strokeDashoffset: CIRCUMFERENCE * (1 - progress.value), 46 | }; 47 | }, []); 48 | 49 | useEffect(() => { 50 | startAnimation(); 51 | }, [startAnimation]); 52 | 53 | const animatedViewStyle = useAnimatedStyle(() => { 54 | return { 55 | // biome-ignore lint/style/useTemplate: false positive 56 | transform: [{ rotate: rotation.value + "deg" }], 57 | }; 58 | }, []); 59 | return ( 60 | 68 | 69 | 70 | 71 | 81 | 82 | 83 | 84 | 85 | ); 86 | } 87 | -------------------------------------------------------------------------------- /native/android/app/src/main/java/com/guardianghost/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.guardianghost 2 | import expo.modules.splashscreen.SplashScreenManager 3 | 4 | import android.os.Build 5 | import android.os.Bundle 6 | 7 | import com.facebook.react.ReactActivity 8 | import com.facebook.react.ReactActivityDelegate 9 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 10 | import com.facebook.react.defaults.DefaultReactActivityDelegate 11 | 12 | import expo.modules.ReactActivityDelegateWrapper 13 | 14 | class MainActivity : ReactActivity() { 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | // Set the theme to AppTheme BEFORE onCreate to support 17 | // coloring the background, status bar, and navigation bar. 18 | // This is required for expo-splash-screen. 19 | // setTheme(R.style.AppTheme); 20 | // @generated begin expo-splashscreen - expo prebuild (DO NOT MODIFY) sync-f3ff59a738c56c9a6119210cb55f0b613eb8b6af 21 | SplashScreenManager.registerOnActivity(this) 22 | // @generated end expo-splashscreen 23 | super.onCreate(null) 24 | } 25 | 26 | /** 27 | * Returns the name of the main component registered from JavaScript. This is used to schedule 28 | * rendering of the component. 29 | */ 30 | override fun getMainComponentName(): String = "main" 31 | 32 | /** 33 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 34 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 35 | */ 36 | override fun createReactActivityDelegate(): ReactActivityDelegate { 37 | return ReactActivityDelegateWrapper( 38 | this, 39 | BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, 40 | object : DefaultReactActivityDelegate( 41 | this, 42 | mainComponentName, 43 | fabricEnabled 44 | ){}) 45 | } 46 | 47 | /** 48 | * Align the back button behavior with Android S 49 | * where moving root activities to background instead of finishing activities. 50 | * @see onBackPressed 51 | */ 52 | override fun invokeDefaultOnBackPressed() { 53 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { 54 | if (!moveTaskToBack(false)) { 55 | // For non-root activities, use the default implementation to finish them. 56 | super.invokeDefaultOnBackPressed() 57 | } 58 | return 59 | } 60 | 61 | // Use the default back button implementation on Android S 62 | // because it's doing more than [Activity.moveTaskToBack] in fact. 63 | super.invokeDefaultOnBackPressed() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /native/app/stats/RecoilStat.tsx: -------------------------------------------------------------------------------- 1 | import { View, StyleSheet } from "react-native"; 2 | import Svg, { Circle, Line, Path } from "react-native-svg"; 3 | import Text from "@/app/UI/Text.tsx"; 4 | 5 | /** 6 | * A value from 100 to -100 where positive is right and negative is left and zero is straight up 7 | * See https://imgur.com/LKwWUNV 8 | */ 9 | function recoilDirection(value: number) { 10 | return Math.sin((value + 5) * (Math.PI / 10)) * (100 - value); 11 | } 12 | 13 | /** 14 | * A value from 0 to 100 describing how straight up and down the recoil is, for sorting 15 | */ 16 | export function recoilValue(value: number) { 17 | const deviation = Math.abs(recoilDirection(value)); 18 | return 100 - deviation + value / 100000; 19 | } 20 | 21 | // How much to bias the direction towards the center - at 1.0 this would mean recoil would swing ±90° 22 | const verticalScale = 0.8; 23 | // The maximum angle of the pie, where zero recoil is the widest and 100 recoil is the narrowest 24 | const maxSpread = 180; // degrees 25 | 26 | type Props = { 27 | readonly value: number; 28 | }; 29 | 30 | export default function RecoilStat({ value }: Props) { 31 | "use memo"; 32 | const direction = recoilDirection(value) * verticalScale * (Math.PI / 180); // Convert to radians 33 | const x = Math.sin(direction); 34 | const y = Math.cos(direction); 35 | 36 | const spread = 37 | // Higher value means less spread 38 | ((100 - value) / 100) * 39 | // scaled by the spread factor (halved since we expand to either side) 40 | (maxSpread / 2) * 41 | // in radians 42 | (Math.PI / 180) * 43 | // flipped for negative 44 | Math.sign(direction); 45 | const xSpreadMore = Math.sin(direction + spread); 46 | const ySpreadMore = Math.cos(direction + spread); 47 | const xSpreadLess = Math.sin(direction - spread); 48 | const ySpreadLess = Math.cos(direction - spread); 49 | 50 | const HEIGHT = 18; 51 | return ( 52 | 53 | {value} 54 | 55 | 56 | {value >= 95 ? ( 57 | 58 | ) : ( 59 | 65 | )} 66 | 67 | 68 | ); 69 | } 70 | 71 | const styles = StyleSheet.create({ 72 | valueText: { 73 | color: "white", 74 | fontSize: 14, 75 | fontWeight: "bold", 76 | includeFontPadding: false, 77 | paddingLeft: 10, 78 | }, 79 | }); 80 | -------------------------------------------------------------------------------- /native/ios/GuardianGhost/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | Guardian Ghost 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 21 | CFBundleShortVersionString 22 | 1.3.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleURLTypes 26 | 27 | 28 | CFBundleURLSchemes 29 | 30 | guardianghost 31 | com.guardianghost.mobile 32 | 33 | 34 | 35 | CFBundleURLSchemes 36 | 37 | exp+nativegg 38 | 39 | 40 | 41 | CFBundleVersion 42 | 478 43 | ITSAppUsesNonExemptEncryption 44 | 45 | LSMinimumSystemVersion 46 | 12.0 47 | LSRequiresIPhoneOS 48 | 49 | NSAppTransportSecurity 50 | 51 | NSAllowsArbitraryLoads 52 | 53 | NSAllowsLocalNetworking 54 | 55 | 56 | RCTNewArchEnabled 57 | 58 | UILaunchStoryboardName 59 | SplashScreen 60 | UIRequiredDeviceCapabilities 61 | 62 | arm64 63 | 64 | UIRequiresFullScreen 65 | 66 | UIStatusBarStyle 67 | UIStatusBarStyleDefault 68 | UISupportedInterfaceOrientations 69 | 70 | UIInterfaceOrientationPortrait 71 | UIInterfaceOrientationPortraitUpsideDown 72 | UIInterfaceOrientationLandscapeLeft 73 | UIInterfaceOrientationLandscapeRight 74 | 75 | UIUserInterfaceStyle 76 | Dark 77 | UIViewControllerBasedStatusBarAppearance 78 | 79 | 80 | -------------------------------------------------------------------------------- /native/app/inventory/pages/InventoryHeader.tsx: -------------------------------------------------------------------------------- 1 | import { Image } from "expo-image"; 2 | import { useEffect } from "react"; 3 | import Animated, { 4 | Extrapolation, 5 | interpolate, 6 | ReduceMotion, 7 | useAnimatedStyle, 8 | useSharedValue, 9 | withSpring, 10 | } from "react-native-reanimated"; 11 | import { View, StyleSheet } from "react-native"; 12 | 13 | import { useGGStore } from "@/app/store/GGStore.ts"; 14 | 15 | export default function InventoryHeader() { 16 | "use memo"; 17 | const currentListIndex = useGGStore((state) => state.currentListIndex); 18 | const characterBackgroundEmblem = useGGStore((state) => state.ggCharacters[currentListIndex]?.secondarySpecial); 19 | const initialPageLoaded = useGGStore((state) => state.initialPageLoaded); 20 | 21 | const opacity = useSharedValue(0); 22 | const viewAnimationStyle = useAnimatedStyle(() => ({ 23 | opacity: interpolate(opacity.value, [0, 1], [0, 1], Extrapolation.CLAMP), 24 | })); 25 | 26 | // biome-ignore lint/correctness/useExhaustiveDependencies: 27 | useEffect(() => { 28 | const checkAndShow = () => { 29 | const initialPageLoaded = useGGStore.getState().initialPageLoaded; 30 | const ggCharacters = useGGStore.getState().ggCharacters; 31 | const currentIndex = useGGStore.getState().currentListIndex; 32 | const emblem = ggCharacters[currentIndex]?.secondarySpecial; 33 | if (initialPageLoaded && ggCharacters.length > 0 && emblem) { 34 | opacity.value = withSpring(1, { 35 | duration: 1250, 36 | reduceMotion: ReduceMotion.System, 37 | }); 38 | } 39 | }; 40 | 41 | // Check initial state 42 | checkAndShow(); 43 | 44 | // Subscribe to initialPageLoaded, ggCharacters, and currentListIndex changes 45 | const unsubscribe1 = useGGStore.subscribe( 46 | (state) => state.initialPageLoaded, 47 | () => { 48 | checkAndShow(); 49 | }, 50 | ); 51 | 52 | const unsubscribe2 = useGGStore.subscribe( 53 | (state) => state.ggCharacters, 54 | () => { 55 | checkAndShow(); 56 | }, 57 | ); 58 | 59 | const unsubscribe3 = useGGStore.subscribe( 60 | (state) => state.currentListIndex, 61 | () => { 62 | checkAndShow(); 63 | }, 64 | ); 65 | 66 | return () => { 67 | unsubscribe1(); 68 | unsubscribe2(); 69 | unsubscribe3(); 70 | }; 71 | }, []); 72 | 73 | return ( 74 | 75 | 76 | 77 | 78 | 87 | 88 | ); 89 | } 90 | -------------------------------------------------------------------------------- /native/app/_authenticated/(drawer)/(tabs)/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { Tabs } from "expo-router"; 2 | import { Platform, View } from "react-native"; 3 | import { Image } from "expo-image"; 4 | import { InventoryPageEnums } from "@/app/inventory/logic/Helpers.ts"; 5 | import { useGGStore } from "@/app/store/GGStore.ts"; 6 | import OptionsMenu from "@/components/ui/OptionsMenu.tsx"; 7 | 8 | function pageEnumToPageName(pageEnum: InventoryPageEnums): string { 9 | switch (pageEnum) { 10 | case InventoryPageEnums.Armor: 11 | return "armor"; 12 | case InventoryPageEnums.General: 13 | return "inventory"; 14 | case InventoryPageEnums.Weapons: 15 | return "weapons"; 16 | } 17 | return "weapons"; 18 | } 19 | 20 | export default function TabsLayout() { 21 | "use memo"; 22 | 23 | const initialRouteName = pageEnumToPageName(useGGStore.getState().currentInventoryPage); 24 | 25 | return ( 26 | 27 | {Platform.OS !== "ios" && } 28 | 39 | { 44 | // eslint-disable-next-line @typescript-eslint/no-require-imports 45 | return ( 46 | 50 | ); 51 | }, 52 | }} 53 | /> 54 | { 59 | // eslint-disable-next-line @typescript-eslint/no-require-imports 60 | return ( 61 | 65 | ); 66 | }, 67 | }} 68 | /> 69 | { 74 | // eslint-disable-next-line @typescript-eslint/no-require-imports 75 | return ( 76 | 80 | ); 81 | }, 82 | }} 83 | /> 84 | 85 | 86 | ); 87 | } 88 | --------------------------------------------------------------------------------