diff --git a/.DS_Store b/.DS_Store index 47a57e45..f7e54ab1 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.github/workflows/deta.yml b/.github/work/deta.yml similarity index 100% rename from .github/workflows/deta.yml rename to .github/work/deta.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/work/workflows/codeql-analysis.yml similarity index 100% rename from .github/workflows/codeql-analysis.yml rename to .github/work/workflows/codeql-analysis.yml diff --git a/.github/workflows/nextjs.yml b/.github/work/workflows/nextjs.yml similarity index 100% rename from .github/workflows/nextjs.yml rename to .github/work/workflows/nextjs.yml diff --git a/.github/work/workflows/pages.yml b/.github/work/workflows/pages.yml new file mode 100644 index 00000000..ed195d1e --- /dev/null +++ b/.github/work/workflows/pages.yml @@ -0,0 +1,93 @@ +# Sample workflow for building and deploying a Next.js site to GitHub Pages +# +# To get started with Next.js see: https://nextjs.org/docs/getting-started +# +name: Deploy Next.js site to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: 'initialClassification' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Detect package manager + id: detect-package-manager + run: | + if [ -f "${{ github.workspace }}/yarn.lock" ]; then + echo "manager=yarn" >> $GITHUB_OUTPUT + echo "command=install" >> $GITHUB_OUTPUT + echo "runner=yarn" >> $GITHUB_OUTPUT + exit 0 + elif [ -f "${{ github.workspace }}/package.json" ]; then + echo "manager=npm" >> $GITHUB_OUTPUT + echo "command=ci" >> $GITHUB_OUTPUT + echo "runner=npx --no-install" >> $GITHUB_OUTPUT + exit 0 + else + echo "Unable to determine package manager" + exit 1 + fi + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: ${{ steps.detect-package-manager.outputs.manager }} + - name: Setup Pages + uses: actions/configure-pages@v5 + with: + # Automatically inject basePath in your Next.js configuration file and disable + # server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized). + # + # You may remove this line if you want to manage the configuration yourself. + static_site_generator: next + - name: Restore cache + uses: actions/cache@v4 + with: + path: | + .next/cache + # Generate a new cache whenever packages or source files change. + key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }} + # If source files changed but packages didn't, rebuild from a prior cache. + restore-keys: | + ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}- + - name: Install dependencies + run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} + - name: Build with Next.js + run: ${{ steps.detect-package-manager.outputs.runner }} next build + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./out + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/.github/work/workflows/preview.yml b/.github/work/workflows/preview.yml new file mode 100644 index 00000000..17580a24 --- /dev/null +++ b/.github/work/workflows/preview.yml @@ -0,0 +1,21 @@ +name: Vercel Preview Deployment +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} +on: + push: + branches-ignore: + - main +jobs: + Deploy-Preview: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Vercel CLI + run: npm install --global vercel@latest + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} + - name: Build Project Artifacts + run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + - name: Deploy Project Artifacts to Vercel + run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} \ No newline at end of file diff --git a/capacitor.config.ts b/capacitor.config.ts deleted file mode 100644 index cea7fe84..00000000 --- a/capacitor.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { CapacitorConfig } from '@capacitor/cli'; - -const config: CapacitorConfig = { - appId: 'space.starsailors.app', - appName: 'Star Sailors', - webDir: 'out', - server: { - androidScheme: 'https' - } -}; - -export default config; \ No newline at end of file diff --git a/components/Authentication/LoginModal.tsx b/components/Authentication/LoginModal.tsx index a67978f8..47b7e01c 100644 --- a/components/Authentication/LoginModal.tsx +++ b/components/Authentication/LoginModal.tsx @@ -1,7 +1,6 @@ import { ReactNode, useEffect } from 'react'; // import { useHistory } from 'react-router-dom'; import Link from 'next/link'; -import Layout from '../_Core/Section/Layout'; import { Auth, ThemeSupa } from '@supabase/auth-ui-react'; import { useSession, useSupabaseClient } from '@supabase/auth-helpers-react'; import { useRouter } from 'next/router'; diff --git a/components/Content/Archive/ArchivedInventory.tsx b/components/Content/Archive/ArchivedInventory.tsx index 4dc64b8b..ae1aa4d3 100644 --- a/components/Content/Archive/ArchivedInventory.tsx +++ b/components/Content/Archive/ArchivedInventory.tsx @@ -1,6 +1,6 @@ import React from "react"; import { useSession, useSupabaseClient } from "@supabase/auth-helpers-react"; -import Layout from "../../_Core/Section/Layout"; +import { SpareLayout } from "../../_Core/Section/Layout"; import OwnedPlanetsList from "./UserOwnedPlanets"; // Potentially this should be in a lists component dir import OwnedItemsList from "../Inventory/UserOwnedItems"; import MySpaceships from "../../Gameplay/Vehicles/MySpaceships"; @@ -10,11 +10,11 @@ export default function V1Inventory() { // Inventory items for v1 of public sche const session = useSession(); return ( - + - + ); }; diff --git a/components/Content/Inventory/UserOwnedItems.tsx b/components/Content/Inventory/UserOwnedItems.tsx index 97603429..03f06da7 100644 --- a/components/Content/Inventory/UserOwnedItems.tsx +++ b/components/Content/Inventory/UserOwnedItems.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react"; import { useSupabaseClient, useSession } from "@supabase/auth-helpers-react"; import Link from "next/link"; -const OwnedItemsList: React.FC = () => { +const OwnedItemsList: React.FC = () => { const supabase = useSupabaseClient(); const session = useSession(); @@ -94,53 +94,80 @@ interface InventoryItem { export const ItemsVerticalList: React.FC = () => { const session = useSession(); - const [itemDetails, setItemDetails] = useState([]); const supabase = useSupabaseClient(); + const [ownedItems, setOwnedItems] = useState([]); + const [itemDetails, setItemDetails] = useState([]); + const [isLoading, setIsLoading] = useState(true); // Loading state useEffect(() => { - const fetchOwnedItems = async () => { + if (!session || !supabase) { + return; + } + + const fetchOwnedItemsAndDetails = async () => { try { - if (!session) return; + setIsLoading(true); + const userId = session.user.id; - const user = session.user.id; // Fetch owned items from the database const { data: ownedItemsData, error: ownedItemsError } = await supabase - .from('inventoryUSERS') - .select('*') - .eq('owner', user) - .gt('id', 20); + .from("inventoryUSERS") + .select("*") + .eq("owner", userId) + .gt("id", 20) + .limit(6) + .order("id", { ascending: false }); if (ownedItemsError) { throw ownedItemsError; } if (ownedItemsData) { + setOwnedItems(ownedItemsData); + + // Extract item IDs from owned items const itemIds = ownedItemsData.map(item => item.item); - // Fetch details of owned items + + // Fetch details of owned items based on item IDs const { data: itemDetailsData, error: itemDetailsError } = await supabase - .from('inventoryITEMS') - .select('*') - .in('id', itemIds); + .from("inventoryITEMS") + .select("*") + .in("id", itemIds); if (itemDetailsError) { throw itemDetailsError; } - if (itemDetailsData) { - setItemDetails(itemDetailsData); - } + setItemDetails(itemDetailsData); } } catch (error) { - console.error('Error fetching owned items:', error.message); + console.error("Error fetching owned items and details:", error); + } finally { + setIsLoading(false); } }; - fetchOwnedItems(); - }, [session]); + fetchOwnedItemsAndDetails(); + }, [session, supabase]); + + // Combine owned items with their details + const combinedItems = ownedItems.map(ownedItem => { + const itemDetail = itemDetails.find(detail => detail.id === ownedItem.item); + return { + ...ownedItem, + ...itemDetail, + }; + }); + + // If the component is loading, you can display a loading indicator or message + if (isLoading) { + return
Loading...
; + } + // Render the list of items return (
- {itemDetails.map(item => ( + {combinedItems.map(item => (
@@ -148,7 +175,7 @@ export const ItemsVerticalList: React.FC = () => {

{item.name}

-

x{item.quantity}

+

{item.quantity}

))}
@@ -224,7 +251,7 @@ export const SectorStructureOwned: React.FC<{ sectorid: string }> = ({ sectorid {item.name}

Quantity: {ownedItem?.quantity}

-

On planet: {ownedItem?.sector}

+

On sector (id): {ownedItem?.sector}

); })} diff --git a/components/Content/Planets/Construction/GlobeClickable.tsx b/components/Content/Planets/Construction/GlobeClickable.tsx new file mode 100644 index 00000000..969b683c --- /dev/null +++ b/components/Content/Planets/Construction/GlobeClickable.tsx @@ -0,0 +1,70 @@ +import { useEffect, useRef } from "react"; +import * as THREE from "three"; +import { Sprite, SpriteMaterial, TextureLoader } from "three"; +import { useFrame } from "@react-three/fiber"; + +interface Landmass { + lat: number; + lng: number; + imageURL: string; + onClickFunction: () => void; +} + +interface ClickableImagesProps { + landmasses: Landmass[]; +} + +function ClickableImages({ landmasses }: ClickableImagesProps) { + const groupRef = useRef(null); + + useEffect(() => { + if (groupRef.current) { + landmasses.forEach((landmass) => { + const { lat, lng, imageURL, onClickFunction } = landmass; + + // Load texture + const textureLoader = new TextureLoader(); + const texture = textureLoader.load(imageURL); + + // Create a sprite with the texture + const spriteMaterial = new SpriteMaterial({ map: texture }); + const sprite = new Sprite(spriteMaterial); + + // Set the size of the sprite + const size = 8; // Adjust size as needed (e.g. 8 for Tailwind scale) + sprite.scale.set(size, size, 1); + + // Convert lat/lng to 3D coordinates + const radius = 100; // Adjust radius as needed + const phi = (90 - lat) * (Math.PI / 180); + const theta = lng * (Math.PI / 180); + sprite.position.set( + radius * Math.sin(phi) * Math.cos(theta), + radius * Math.cos(phi), + radius * Math.sin(phi) * Math.sin(theta) + ); + + // Create a click handler for the sprite + const handleClick = (event: any) => { + event.stopPropagation(); + onClickFunction(); + }; + + // Add event listener to the sprite for the 'click' event + sprite.addEventListener('click', handleClick); + + // Add the sprite to the group + groupRef.current.add(sprite); + }); + } + }, [landmasses]); + + // Use useFrame hook to continuously update the scene if needed + useFrame(() => { + // Add any animation logic here if required + }); + + return ; +} + +export default ClickableImages; \ No newline at end of file diff --git a/components/Content/Planets/PlanetGlobe.tsx b/components/Content/Planets/PlanetGlobe.tsx new file mode 100644 index 00000000..1bdfad1d --- /dev/null +++ b/components/Content/Planets/PlanetGlobe.tsx @@ -0,0 +1,304 @@ +import { useEffect, useRef, useState } from "react"; +import { Color, Scene, Fog, PerspectiveCamera, Vector3 } from "three"; +import ThreeGlobe from "three-globe"; +import { useThree, Object3DNode, Canvas, extend } from "@react-three/fiber"; +import { OrbitControls } from "@react-three/drei"; +import countries from "../../../context/data/globe.json"; +declare module "@react-three/fiber" { + interface ThreeElements { + threeGlobe: Object3DNode; + } +} + +extend({ ThreeGlobe }); + +const RING_PROPAGATION_SPEED = 3; +const aspect = 1.2; +const cameraZ = 300; + +type Position = { + order: number; + startLat: number; + startLng: number; + endLat: number; + endLng: number; + arcAlt: number; + color: string; +}; + +export type GlobeConfig = { + pointSize?: number; + globeColor?: string; + showAtmosphere?: boolean; + atmosphereColor?: string; + atmosphereAltitude?: number; + emissive?: string; + emissiveIntensity?: number; + shininess?: number; + polygonColor?: string; + ambientLight?: string; + directionalLeftLight?: string; + directionalTopLight?: string; + pointLight?: string; + arcTime?: number; + arcLength?: number; + rings?: number; + maxRings?: number; + initialPosition?: { + lat: number; + lng: number; + }; + autoRotate?: boolean; + autoRotateSpeed?: number; +}; + +interface WorldProps { + globeConfig: GlobeConfig; + data: Position[]; +} + +let numbersOfRings = [0]; + +export function Globe({ globeConfig, data }: WorldProps) { + const [globeData, setGlobeData] = useState< + | { + size: number; + order: number; + color: (t: number) => string; + lat: number; + lng: number; + }[] + | null + >(null); + + const globeRef = useRef(null); + + const defaultProps = { + pointSize: 1, + atmosphereColor: "#ffffff", + showAtmosphere: true, + atmosphereAltitude: 0.1, + polygonColor: "rgba(255,255,255,0.7)", + globeColor: "#1d072e", + emissive: "#000000", + emissiveIntensity: 0.1, + shininess: 0.9, + arcTime: 2000, + arcLength: 0.9, + rings: 1, + maxRings: 3, + ...globeConfig, + }; + + useEffect(() => { + if (globeRef.current) { + _buildData(); + _buildMaterial(); + } + }, [globeRef.current]); + + const _buildMaterial = () => { + if (!globeRef.current) return; + + const globeMaterial = globeRef.current.globeMaterial() as unknown as { + color: Color; + emissive: Color; + emissiveIntensity: number; + shininess: number; + }; + globeMaterial.color = new Color(globeConfig.globeColor); + globeMaterial.emissive = new Color(globeConfig.emissive); + globeMaterial.emissiveIntensity = globeConfig.emissiveIntensity || 0.1; + globeMaterial.shininess = globeConfig.shininess || 0.9; + }; + + const _buildData = () => { + const arcs = data; + let points = []; + for (let i = 0; i < arcs.length; i++) { + const arc = arcs[i]; + const rgb = hexToRgb(arc.color) as { r: number; g: number; b: number }; + points.push({ + size: defaultProps.pointSize, + order: arc.order, + color: (t: number) => `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${1 - t})`, + lat: arc.startLat, + lng: arc.startLng, + }); + points.push({ + size: defaultProps.pointSize, + order: arc.order, + color: (t: number) => `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${1 - t})`, + lat: arc.endLat, + lng: arc.endLng, + }); + } + + // remove duplicates for same lat and lng + const filteredPoints = points.filter( + (v, i, a) => + a.findIndex((v2) => + ["lat", "lng"].every( + (k) => v2[k as "lat" | "lng"] === v[k as "lat" | "lng"] + ) + ) === i + ); + + setGlobeData(filteredPoints); + }; + + useEffect(() => { + if (globeRef.current && globeData) { + globeRef.current + .hexPolygonsData(countries.features) + .hexPolygonResolution(3) + .hexPolygonMargin(0.7) + .showAtmosphere(defaultProps.showAtmosphere) + .atmosphereColor(defaultProps.atmosphereColor) + .atmosphereAltitude(defaultProps.atmosphereAltitude) + .hexPolygonColor((e) => { + return defaultProps.polygonColor; + }); + startAnimation(); + } + }, [globeData]); + + const startAnimation = () => { + if (!globeRef.current || !globeData) return; + + globeRef.current + .arcsData(data) + .arcStartLat((d) => (d as { startLat: number }).startLat * 1) + .arcStartLng((d) => (d as { startLng: number }).startLng * 1) + .arcEndLat((d) => (d as { endLat: number }).endLat * 1) + .arcEndLng((d) => (d as { endLng: number }).endLng * 1) + .arcColor((e: any) => (e as { color: string }).color) + .arcAltitude((e) => { + return (e as { arcAlt: number }).arcAlt * 1; + }) + .arcStroke((e) => { + return [0.32, 0.28, 0.3][Math.round(Math.random() * 2)]; + }) + .arcDashLength(defaultProps.arcLength) + .arcDashInitialGap((e) => (e as { order: number }).order * 1) + .arcDashGap(15) + .arcDashAnimateTime((e) => defaultProps.arcTime); + + globeRef.current + .pointsData(data) + .pointColor((e) => (e as { color: string }).color) + .pointsMerge(true) + .pointAltitude(0.0) + .pointRadius(2); + + globeRef.current + .ringsData([]) + .ringColor((e: any) => (t: any) => e.color(t)) + .ringMaxRadius(defaultProps.maxRings) + .ringPropagationSpeed(RING_PROPAGATION_SPEED) + .ringRepeatPeriod( + (defaultProps.arcTime * defaultProps.arcLength) / defaultProps.rings + ); + }; + + useEffect(() => { + if (!globeRef.current || !globeData) return; + + const interval = setInterval(() => { + if (!globeRef.current || !globeData) return; + numbersOfRings = genRandomNumbers( + 0, + data.length, + Math.floor((data.length * 4) / 5) + ); + + globeRef.current.ringsData( + globeData.filter((d, i) => numbersOfRings.includes(i)) + ); + }, 2000); + + return () => { + clearInterval(interval); + }; + }, [globeRef.current, globeData]); + + return ( + <> + + + ); +} + +export function WebGLRendererConfig() { + const { gl, size } = useThree(); + + useEffect(() => { + gl.setPixelRatio(window.devicePixelRatio); + gl.setSize(size.width, size.height); + gl.setClearColor(0xffaaff, 0); + }, []); + + return null; +} + +export function World(props: WorldProps) { + const { globeConfig } = props; + const scene = new Scene(); + scene.fog = new Fog(0xffffff, 400, 2000); + return ( + + + + + + + + + + ); +} + +export function hexToRgb(hex: string) { + var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + hex = hex.replace(shorthandRegex, function (m, r, g, b) { + return r + r + g + g + b + b; + }); + + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result + ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16), + } + : null; +}; + +export function genRandomNumbers(min: number, max: number, count: number) { + const arr = []; + while (arr.length < count) { + const r = Math.floor(Math.random() * (max - min)) + min; + if (arr.indexOf(r) === -1) arr.push(r); + } + + return arr; +} diff --git a/components/Content/Planets/PlanetGlobeTest.tsx b/components/Content/Planets/PlanetGlobeTest.tsx new file mode 100644 index 00000000..032c758c --- /dev/null +++ b/components/Content/Planets/PlanetGlobeTest.tsx @@ -0,0 +1,428 @@ +"use client"; +import React from "react"; +import { motion } from "framer-motion"; +import dynamic from "next/dynamic"; + +const World = dynamic(() => import("./PlanetGlobe").then((m) => m.World), { + ssr: false, +}); + +export function GlobeDemo() { + const globeConfig = { + pointSize: 4, + globeColor: "#062056", + showAtmosphere: false, + atmosphereColor: "#FFFFFF", + atmosphereAltitude: 0.4, + emissive: "#06b6d4", + emissiveIntensity: 0.1, + shininess: 0.3, + polygonColor: "rgba(255,255,255,0.7)", + ambientLight: "#38bdf8", + directionalLeftLight: "#ffffff", + directionalTopLight: "#ffffff", + pointLight: "#ffffff", + arcTime: 1000, + arcLength: 0.9, + rings: 5, + maxRings: 9, + initialPosition: { lat: 22.3193, lng: 114.1694 }, + autoRotate: true, + autoRotateSpeed: 0.23, + }; + const colors = ["#06b6d4", "06b6d4", "#6366f1"]; + const sampleArcs = [ + { + order: 1, + startLat: -19.885592, + startLng: -43.951191, + endLat: -22.9068, + endLng: -43.1729, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 1, + startLat: 28.6139, + startLng: 77.209, + endLat: 3.139, + endLng: 101.6869, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 1, + startLat: -19.885592, + startLng: -43.951191, + endLat: -1.303396, + endLng: 36.852443, + arcAlt: 0.5, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 2, + startLat: 1.3521, + startLng: 103.8198, + endLat: 35.6762, + endLng: 139.6503, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 2, + startLat: 51.5072, + startLng: -0.1276, + endLat: 3.139, + endLng: 101.6869, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 2, + startLat: -15.785493, + startLng: -47.909029, + endLat: 36.162809, + endLng: -115.119411, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 3, + startLat: -33.8688, + startLng: 151.2093, + endLat: 22.3193, + endLng: 114.1694, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 3, + startLat: 21.3099, + startLng: -157.8581, + endLat: 40.7128, + endLng: -74.006, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 3, + startLat: -6.2088, + startLng: 106.8456, + endLat: 51.5072, + endLng: -0.1276, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 4, + startLat: 11.986597, + startLng: 8.571831, + endLat: -15.595412, + endLng: -56.05918, + arcAlt: 0.5, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 4, + startLat: -34.6037, + startLng: -58.3816, + endLat: 22.3193, + endLng: 114.1694, + arcAlt: 0.7, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 4, + startLat: 51.5072, + startLng: -0.1276, + endLat: 48.8566, + endLng: -2.3522, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 5, + startLat: 14.5995, + startLng: 120.9842, + endLat: 51.5072, + endLng: -0.1276, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 5, + startLat: 1.3521, + startLng: 103.8198, + endLat: -33.8688, + endLng: 151.2093, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 5, + startLat: 34.0522, + startLng: -118.2437, + endLat: 48.8566, + endLng: -2.3522, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 6, + startLat: -15.432563, + startLng: 28.315853, + endLat: 1.094136, + endLng: -63.34546, + arcAlt: 0.7, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 6, + startLat: 37.5665, + startLng: 126.978, + endLat: 35.6762, + endLng: 139.6503, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 6, + startLat: 22.3193, + startLng: 114.1694, + endLat: 51.5072, + endLng: -0.1276, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 7, + startLat: -19.885592, + startLng: -43.951191, + endLat: -15.595412, + endLng: -56.05918, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 7, + startLat: 48.8566, + startLng: -2.3522, + endLat: 52.52, + endLng: 13.405, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 7, + startLat: 52.52, + startLng: 13.405, + endLat: 34.0522, + endLng: -118.2437, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 8, + startLat: -8.833221, + startLng: 13.264837, + endLat: -33.936138, + endLng: 18.436529, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 8, + startLat: 49.2827, + startLng: -123.1207, + endLat: 52.3676, + endLng: 4.9041, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 8, + startLat: 1.3521, + startLng: 103.8198, + endLat: 40.7128, + endLng: -74.006, + arcAlt: 0.5, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 9, + startLat: 51.5072, + startLng: -0.1276, + endLat: 34.0522, + endLng: -118.2437, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 9, + startLat: 22.3193, + startLng: 114.1694, + endLat: -22.9068, + endLng: -43.1729, + arcAlt: 0.7, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 9, + startLat: 1.3521, + startLng: 103.8198, + endLat: -34.6037, + endLng: -58.3816, + arcAlt: 0.5, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 10, + startLat: -22.9068, + startLng: -43.1729, + endLat: 28.6139, + endLng: 77.209, + arcAlt: 0.7, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 10, + startLat: 34.0522, + startLng: -118.2437, + endLat: 31.2304, + endLng: 121.4737, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 10, + startLat: -6.2088, + startLng: 106.8456, + endLat: 52.3676, + endLng: 4.9041, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 11, + startLat: 41.9028, + startLng: 12.4964, + endLat: 34.0522, + endLng: -118.2437, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 11, + startLat: -6.2088, + startLng: 106.8456, + endLat: 31.2304, + endLng: 121.4737, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 11, + startLat: 22.3193, + startLng: 114.1694, + endLat: 1.3521, + endLng: 103.8198, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 12, + startLat: 34.0522, + startLng: -118.2437, + endLat: 37.7749, + endLng: -122.4194, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 12, + startLat: 35.6762, + startLng: 139.6503, + endLat: 22.3193, + endLng: 114.1694, + arcAlt: 0.2, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 12, + startLat: 22.3193, + startLng: 114.1694, + endLat: 34.0522, + endLng: -118.2437, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 13, + startLat: 52.52, + startLng: 13.405, + endLat: 22.3193, + endLng: 114.1694, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 13, + startLat: 11.986597, + startLng: 8.571831, + endLat: 35.6762, + endLng: 139.6503, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 13, + startLat: -22.9068, + startLng: -43.1729, + endLat: -34.6037, + endLng: -58.3816, + arcAlt: 0.1, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + { + order: 14, + startLat: -33.936138, + startLng: 18.436529, + endLat: 21.395643, + endLng: 39.883798, + arcAlt: 0.3, + color: colors[Math.floor(Math.random() * (colors.length - 1))], + }, + ]; + + return ( +
+
+ +

+ {/* Content */} +

+

+ {/* Content */} +

+
+
+
+ ; +
+
+
+ ); +}; \ No newline at end of file diff --git a/components/Content/Visuals/Bento.tsx b/components/Content/Visuals/Bento.tsx new file mode 100644 index 00000000..376ed694 --- /dev/null +++ b/components/Content/Visuals/Bento.tsx @@ -0,0 +1,357 @@ +"use client"; +import { cn } from "../../../lib/uitls"; +import React from "react"; +import { BentoGrid, BentoGridItem } from "../../_Core/ui/bento-grid"; +import { + IconBoxAlignRightFilled, + IconClipboardCopy, + IconFileBroken, + IconSignature, + IconTableColumn, +} from "@tabler/icons-react"; +import { motion } from "framer-motion"; +import Image from "next/image"; +import { ItemsVerticalList } from "../Inventory/UserOwnedItems"; +// import { MissionList } from "../../Gameplay/mission-list"; + +export function BentoGridThirdDemo() { + return (<> + // + // {items.map((item, i) => ( + // p:text-lg]", item.className)} + // icon={item.icon} + // /> + // ))} + // + ); +} + +export function BentoGridMobileDemo() { + return ( + + {mobileItems.map((item, i) => ( + p:text-lg]", item.className)} + icon={item.icon} + /> + ))} + + ); +} + +const Skeleton = () => ( +
+); + +const SkeletonOne = () => { + const variants = { + initial: { + x: 0, + }, + animate: { + x: 10, + rotate: 5, + transition: { + duration: 0.2, + }, + }, + }; + const variantsSecond = { + initial: { + x: 0, + }, + animate: { + x: -10, + rotate: -5, + transition: { + duration: 0.2, + }, + }, + }; + + return ( + + +
+
+ + +
+
+ + +
+
+ + + ); +}; +const SkeletonTwo = () => { + const variants = { + initial: { + width: 0, + }, + animate: { + width: "100%", + transition: { + duration: 0.2, + }, + }, + hover: { + width: ["0%", "100%"], + transition: { + duration: 2, + }, + }, + }; + const arr = new Array(6).fill(0); + return ( + + {arr.map((_, i) => ( + + ))} + + ); +}; +const SkeletonThree = () => { + const variants = { + initial: { + backgroundPosition: "0 50%", + }, + animate: { + backgroundPosition: ["0, 50%", "100% 50%", "0 50%"], + }, + }; + return ( + + + + ); +}; +const SkeletonFour = () => { + const first = { + initial: { + x: 20, + rotate: -5, + }, + hover: { + x: 0, + rotate: 0, + }, + }; + const second = { + initial: { + x: -20, + rotate: 5, + }, + hover: { + x: 0, + rotate: 0, + }, + }; + return ( + + {/* */} + + ); +}; +const SkeletonFive = () => { + const variants = { + initial: { + x: 0, + }, + animate: { + x: 2, + rotate: 1.3, + transition: { + duration: 0.2, + }, + }, + }; + const variantsSecond = { + initial: { + x: 0, + }, + animate: { + x: -10, + rotate: -5, + transition: { + duration: 0.2, + }, + }, + }; + + return ( + + + + + + ); +}; +const items = [ + { + title: "AI Content Generation", + description: ( + + Experience the power of AI in generating unique content. + + ), + header: , + className: "md:col-span-1", + // icon: , + }, + { + title: "Automated Proofreading", + description: ( + + Let AI handle the proofreading of your documents. + + ), + header: , + className: "md:col-span-1", + // icon: , + }, + { + title: "Contextual Suggestions", + description: ( + + Get AI-powered suggestions based on your writing context. + + ), + header: , + className: "md:col-span-1", + // icon: , + }, + { + title: "", + description: ( + null + ), + header: , + className: "md:col-span-2", + // icon: , + }, + + { + title: "", + description: ( + null + ), + header: , + className: "md:col-span-1", + // icon: , + }, +]; + +const mobileItems = [ + { + title: "AI Content Generation", + description: ( + + Experience the power of AI in generating unique content. + + ), + header: , + className: "md:col-span-1", + icon: , + }, + { + title: "", + description: ( + null + ), + header: , + className: "md:col-span-2", + icon: , + }, + ]; + + +/* +
+
+ {/*
+ {isDesktopOrLaptop && ( + <> + Planet 1 + Planet 2 + + )} + {isTabletOrMobile && ( + <> + Planet 1 + Planet 2 + + )} +
+
+ {isDesktopOrLaptop && ()} +
+
+
+ + +
+
*/ \ No newline at end of file diff --git a/components/Gameplay/mission-list.tsx b/components/Gameplay/mission-list.tsx new file mode 100644 index 00000000..37a77401 --- /dev/null +++ b/components/Gameplay/mission-list.tsx @@ -0,0 +1,64 @@ +import { CardTitle, CardDescription, CardHeader, CardContent, CardFooter, Card } from "../ui/card"; +import Link from "next/link"; +import { Button } from "../ui/button"; + +export function MissionList() { + const missions = [ + { name: "Pick your home planet", completed: true }, + { name: "Build your first rover", completed: false }, + { name: "Collect your first resources", completed: false }, + { name: "Build your first structure", completed: false }, + { name: "Make your first classification", completed: false }, + ]; + + return ( + <> + + To-Do List + Manage your daily tasks + + + {missions.map((mission, index) => ( +
+
+ + + +

+ {mission.name} +

+
+
+ ))} +
+ + ); +} + +function LinkIcon(props) { + return ( + + + + + ) +} \ No newline at end of file diff --git a/components/Modals/rover-interface.tsx b/components/Modals/rover-interface.tsx index 5e84dfa5..d38a2a68 100644 --- a/components/Modals/rover-interface.tsx +++ b/components/Modals/rover-interface.tsx @@ -466,6 +466,122 @@ export function RoverInterfaceDark() { ); }; +export function RoverInterfaceDarkMobile() { + return ( +
+
+
+
Planet Name
+
+
ROVER #1 (Allow user to customise name)
+
+
+
MISSION DAY
+
SOL #3039
+
Time: 2:36 pm
+
+
+
SUNRISE
+
6:37 am
+
SUNSET
+
6:35 pm
+
+
+
+
+
+
PRESSURE
+
+ + 827 Pa +
+
+
+
OXYGEN
+
+ + 0.24% +
+
+
+
+
TEMPERATURE
+
+ + -29.16 °C +
+
+
+
ATMOSPHERE
+
Moderate sunny
+
+
+
ROVER STATUS
+
+
+
CELL
+
65.25
+
+
+
GAS PRESS
+
12.48
+
+
+
+
MODE
+
DRV
+
+
+
+
SPEED
+
118 km/hour
+
+
+
+
CAMERA CONTROL PANEL
+
+
+
+
+ + + +
+
+ + + +
+
+
+