2 Commits

25 changed files with 148 additions and 157 deletions

View File

@@ -2,12 +2,12 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { import {
Breadcrumb, Breadcrumb,
BreadcrumbItem, BreadcrumbItem,
BreadcrumbLink, BreadcrumbLink,
BreadcrumbList, BreadcrumbList,
BreadcrumbPage, BreadcrumbPage,
BreadcrumbSeparator, BreadcrumbSeparator,
} from '@/components/ui/breadcrumb'; } from '@/components/ui/breadcrumb';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { toast } from '@/hooks/use-toast'; import { toast } from '@/hooks/use-toast';
@@ -31,7 +31,7 @@ export const Header = ({ title, breadcrumbs = [] }: HeaderProps) => {
try { try {
const list = await ListCharacters(); const list = await ListCharacters();
setChars((list as any[]).map((c: any) => ({ character_id: c.character_id, character_name: c.character_name }))); setChars((list as any[]).map((c: any) => ({ character_id: c.character_id, character_name: c.character_name })));
} catch {} } catch { }
}; };
useEffect(() => { useEffect(() => {
@@ -84,7 +84,7 @@ export const Header = ({ title, breadcrumbs = [] }: HeaderProps) => {
</Breadcrumb> </Breadcrumb>
</div> </div>
)} )}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<h1 className="text-2xl font-bold text-white">{title}</h1> <h1 className="text-2xl font-bold text-white">{title}</h1>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">

View File

@@ -96,7 +96,7 @@ export const RegionMap = ({ regionName, focusSystem, isCompact = false, isWormho
type OffIndicator = { from: string; toRegion: string; count: number; color: string; angle: number; sampleTo?: string }; type OffIndicator = { from: string; toRegion: string; count: number; color: string; angle: number; sampleTo?: string };
const [offRegionIndicators, setOffRegionIndicators] = useState<OffIndicator[]>([]); const [offRegionIndicators, setOffRegionIndicators] = useState<OffIndicator[]>([]);
const [meanInboundAngle, setMeanInboundAngle] = useState<Record<string, number>>({}); const [meanNeighborAngle, setMeanNeighborAngle] = useState<Record<string, number>>({});
const [charLocs, setCharLocs] = useState<Array<{ character_id: number; character_name: string; solar_system_name: string }>>([]); const [charLocs, setCharLocs] = useState<Array<{ character_id: number; character_name: string; solar_system_name: string }>>([]);
useEffect(() => { useEffect(() => {
@@ -133,7 +133,7 @@ export const RegionMap = ({ regionName, focusSystem, isCompact = false, isWormho
setPositions(positions); setPositions(positions);
const connections = computeNodeConnections(systems); const connections = computeNodeConnections(systems);
setConnections(connections); setConnections(connections);
// Compute per-system mean outbound BEARING (0=north, clockwise positive) to in-region neighbors // Compute per-system mean outbound angle in screen coords (atan2(dy,dx)) to in-region neighbors
const angleMap: Record<string, number> = {}; const angleMap: Record<string, number> = {};
systems.forEach((sys, name) => { systems.forEach((sys, name) => {
const neighbors = (sys.connectedSystems || '').split(',').map(s => s.trim()).filter(Boolean); const neighbors = (sys.connectedSystems || '').split(',').map(s => s.trim()).filter(Boolean);
@@ -142,17 +142,17 @@ export const RegionMap = ({ regionName, focusSystem, isCompact = false, isWormho
const neighbor = systems.get(n); const neighbor = systems.get(n);
if (!neighbor) continue; if (!neighbor) continue;
const dx = neighbor.x - sys.x; const dx = neighbor.x - sys.x;
const dy = neighbor.y - sys.y; // screen coords (y down) const dy = neighbor.y - sys.y; // y-down screen
const bearing = Math.atan2(dx, -dy); // bearing relative to north const a = Math.atan2(dy, dx);
sumSin += Math.sin(bearing); sumSin += Math.sin(a);
sumCos += Math.cos(bearing); sumCos += Math.cos(a);
count++; count++;
} }
if (count > 0) { if (count > 0) {
angleMap[name] = Math.atan2(sumSin, sumCos); // average bearing angleMap[name] = Math.atan2(sumSin, sumCos); // average angle
} }
}); });
setMeanInboundAngle(angleMap); setMeanNeighborAngle(angleMap);
}, [systems]); }, [systems]);
// Poll character locations every 7s and store those in this region // Poll character locations every 7s and store those in this region
@@ -208,58 +208,49 @@ export const RegionMap = ({ regionName, focusSystem, isCompact = false, isWormho
} }
await ensureUniversePositions(); await ensureUniversePositions();
// Build indicators: group by from+toRegion // Build indicators: group by from+toRegion; angle from local geometry only (meanNeighborAngle + PI)
const grouped: Map<string, OffIndicator> = new Map(); type Agg = { from: string; toRegion: string; count: number; sumRemoteSec: number; sampleTo?: string };
const grouped: Map<string, Agg> = new Map();
for (const [fromName, sys] of systems.entries()) { for (const [fromName, sys] of systems.entries()) {
const neighbors = (sys.connectedSystems || '').split(',').map(s => s.trim()).filter(Boolean); const neighbors = (sys.connectedSystems || '').split(',').map(s => s.trim()).filter(Boolean);
for (const n of neighbors) { for (const n of neighbors) {
if (systems.has(n)) continue; if (systems.has(n)) continue;
const toRegion = nameToRegion[n]; const toRegion = nameToRegion[n];
if (!toRegion || toRegion === regionName) continue; if (!toRegion || toRegion === regionName) continue;
// compute color
const remote = regionSystemsCache.get(toRegion)?.get(n); const remote = regionSystemsCache.get(toRegion)?.get(n);
const avgSec = ((sys.security || 0) + (remote?.security || 0)) / 2;
const color = getSecurityColor(avgSec);
// compute angle via universe region centroids
let angle: number | undefined = undefined;
const inbound = meanInboundAngle[fromName];
if (inbound !== undefined) {
angle = inbound; // mean outbound bearing already computed
} else {
const curPos = universeRegionPosCache.get(regionName);
const toPos = universeRegionPosCache.get(toRegion);
if (curPos && toPos) {
const dxr = toPos.x - curPos.x;
const dyr = toPos.y - curPos.y;
angle = Math.atan2(dxr, -dyr); // bearing to remote region
}
}
if (angle === undefined) {
// final fallback deterministic angle
let h = 0; const key = `${fromName}->${toRegion}`;
for (let i = 0; i < key.length; i++) h = (h * 31 + key.charCodeAt(i)) >>> 0;
angle = (h % 360) * (Math.PI / 180);
}
// Flip 180° so indicator points away from existing connections
angle = angle + Math.PI;
const gkey = `${fromName}__${toRegion}`; const gkey = `${fromName}__${toRegion}`;
const prev = grouped.get(gkey); const agg = grouped.get(gkey) || { from: fromName, toRegion, count: 0, sumRemoteSec: 0, sampleTo: n };
if (prev) { agg.count += 1;
prev.count += 1; if (remote) agg.sumRemoteSec += (remote.security || 0);
if (!prev.sampleTo) prev.sampleTo = n; grouped.set(gkey, agg);
} else {
grouped.set(gkey, { from: fromName, toRegion, count: 1, color, angle, sampleTo: n });
}
} }
} }
const out: OffIndicator[] = [];
for (const [, agg] of grouped) {
if (agg.count === 0) continue;
// Angle: point away from existing connections = meanNeighborAngle + PI
let angle = meanNeighborAngle[agg.from];
if (angle === undefined) {
// fallback: away from region centroid
// compute centroid of current region nodes
let cx = 0, cy = 0, c = 0;
systems.forEach(s => { cx += s.x; cy += s.y; c++; });
if (c > 0) { cx /= c; cy /= c; }
const sys = systems.get(agg.from)!;
angle = Math.atan2(sys.y - cy, sys.x - cx);
}
angle = angle + Math.PI;
setOffRegionIndicators(Array.from(grouped.values())); // Color from avg of local system sec and avg remote sec; local from this system
const localSec = (systems.get(agg.from)?.security || 0);
const remoteAvg = agg.count > 0 ? (agg.sumRemoteSec / agg.count) : 0;
const color = getSecurityColor((localSec + remoteAvg) / 2);
out.push({ from: agg.from, toRegion: agg.toRegion, count: agg.count, color, angle, sampleTo: agg.sampleTo });
}
setOffRegionIndicators(out);
}; };
computeOffRegion(); computeOffRegion();
}, [systems, regionName]); }, [systems, regionName, meanNeighborAngle]);
useEffect(() => { useEffect(() => {
if (isWormholeRegion) { if (isWormholeRegion) {
@@ -686,8 +677,8 @@ export const RegionMap = ({ regionName, focusSystem, isCompact = false, isWormho
if (!pos) return null; if (!pos) return null;
const len = 26; const len = 26;
const r0 = 10; // start just outside node const r0 = 10; // start just outside node
const dx = Math.sin(ind.angle); const dx = Math.cos(ind.angle);
const dy = -Math.cos(ind.angle); const dy = Math.sin(ind.angle);
const x1 = pos.x + dx * r0; const x1 = pos.x + dx * r0;
const y1 = pos.y + dy * r0; const y1 = pos.y + dy * r0;
const x2 = x1 + dx * len; const x2 = x1 + dx * len;

View File

@@ -3,15 +3,15 @@ import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
AlertDialog, AlertDialog,
AlertDialogAction, AlertDialogAction,
AlertDialogCancel, AlertDialogCancel,
AlertDialogContent, AlertDialogContent,
AlertDialogDescription, AlertDialogDescription,
AlertDialogFooter, AlertDialogFooter,
AlertDialogHeader, AlertDialogHeader,
AlertDialogTitle, AlertDialogTitle,
AlertDialogTrigger, AlertDialogTrigger,
} from "@/components/ui/alert-dialog"; } from "@/components/ui/alert-dialog";
import { SigviewRecord as Signature } from "@/lib/pbtypes"; import { SigviewRecord as Signature } from "@/lib/pbtypes";
import { getSignatureMeta } from "@/hooks/useSignatureCategories"; import { getSignatureMeta } from "@/hooks/useSignatureCategories";
@@ -52,7 +52,7 @@ export const SignatureCard = ({ signature, onDelete, onUpdate }: SignatureCardPr
return ( return (
<> <>
<Card <Card
className={`${isGasSite ? 'bg-emerald-900/40 border-emerald-500 shadow-[0_0_15px_rgba(16,185,129,0.5)] hover:shadow-[0_0_20px_rgba(16,185,129,0.7)]' : 'bg-slate-800/40 border-slate-700'} hover:bg-slate-800/60 transition-all duration-200 hover:border-slate-600 relative cursor-pointer`} className={`${isGasSite ? 'bg-emerald-900/40 border-emerald-500 shadow-[0_0_15px_rgba(16,185,129,0.5)] hover:shadow-[0_0_20px_rgba(16,185,129,0.7)]' : 'bg-slate-800/40 border-slate-700'} hover:bg-slate-800/60 transition-all duration-200 hover:border-slate-600 relative cursor-pointer`}
onClick={() => setIsEditModalOpen(true)} onClick={() => setIsEditModalOpen(true)}
> >
@@ -60,15 +60,15 @@ export const SignatureCard = ({ signature, onDelete, onUpdate }: SignatureCardPr
<div className="space-y-3"> <div className="space-y-3">
{/* Type Badge - Most Important */} {/* Type Badge - Most Important */}
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<Badge <Badge
variant="outline" variant="outline"
className={`${meta.color} px-3 py-1 text-sm font-semibold flex items-center gap-2`} className={`${meta.color} px-3 py-1 text-sm font-semibold flex items-center gap-2`}
> >
{meta.icon} {meta.icon}
{signature.type || 'Unknown Type'} {signature.type || 'Unknown Type'}
</Badge> </Badge>
</div> </div>
{/* Signature Name */} {/* Signature Name */}
<div className="text-center"> <div className="text-center">
<h3 className="text-white font-medium text-lg"> <h3 className="text-white font-medium text-lg">
@@ -82,7 +82,7 @@ export const SignatureCard = ({ signature, onDelete, onUpdate }: SignatureCardPr
</div> </div>
)} )}
</div> </div>
{/* Additional Info */} {/* Additional Info */}
<div className="space-y-2 text-sm text-slate-400"> <div className="space-y-2 text-sm text-slate-400">
<div className="flex justify-between"> <div className="flex justify-between">

View File

@@ -53,9 +53,9 @@ export const SignatureCategories = ({ categories, onToggleCategory, onDelete, on
<CardContent className="p-0"> <CardContent className="p-0">
<div className="divide-y divide-slate-700"> <div className="divide-y divide-slate-700">
{category.signatures.map((signature) => ( {category.signatures.map((signature) => (
<SignatureListItem <SignatureListItem
key={signature.id} key={signature.id}
signature={signature} signature={signature}
onDelete={onDelete} onDelete={onDelete}
onUpdate={onUpdate} onUpdate={onUpdate}
/> />

View File

@@ -1,12 +1,12 @@
import { useState } from "react"; import { useState } from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
DialogDescription, DialogDescription,
DialogFooter, DialogFooter,
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";

View File

@@ -2,15 +2,15 @@ import { useState } from "react";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
AlertDialog, AlertDialog,
AlertDialogAction, AlertDialogAction,
AlertDialogCancel, AlertDialogCancel,
AlertDialogContent, AlertDialogContent,
AlertDialogDescription, AlertDialogDescription,
AlertDialogFooter, AlertDialogFooter,
AlertDialogHeader, AlertDialogHeader,
AlertDialogTitle, AlertDialogTitle,
AlertDialogTrigger, AlertDialogTrigger,
} from "@/components/ui/alert-dialog"; } from "@/components/ui/alert-dialog";
import { Clock, AlertTriangle, Skull, Trash2 } from "lucide-react"; import { Clock, AlertTriangle, Skull, Trash2 } from "lucide-react";
import { SigviewRecord as Signature } from "@/lib/pbtypes"; import { SigviewRecord as Signature } from "@/lib/pbtypes";
@@ -88,9 +88,8 @@ export const SignatureListItem = ({ signature, onDelete, onUpdate }: SignatureLi
return ( return (
<> <>
<div <div
className={`flex items-center justify-between p-4 border-b border-slate-700 hover:bg-slate-800/40 transition-colors cursor-pointer ${ className={`flex items-center justify-between p-4 border-b border-slate-700 hover:bg-slate-800/40 transition-colors cursor-pointer ${oldEntry ? "opacity-50" : ""
oldEntry ? "opacity-50" : "" } ${isGasSite ? 'bg-emerald-900/40 border-emerald-500 shadow-[0_0_15px_rgba(16,185,129,0.5)] hover:shadow-[0_0_20px_rgba(16,185,129,0.7)]' : ''}`}
} ${isGasSite ? 'bg-emerald-900/40 border-emerald-500 shadow-[0_0_15px_rgba(16,185,129,0.5)] hover:shadow-[0_0_20px_rgba(16,185,129,0.7)]' : ''}`}
onClick={() => setIsEditModalOpen(true)} onClick={() => setIsEditModalOpen(true)}
> >
<div className="flex items-center gap-4 flex-1"> <div className="flex items-center gap-4 flex-1">

View File

@@ -25,7 +25,7 @@ const badgeVariants = cva(
export interface BadgeProps export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>, extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {} VariantProps<typeof badgeVariants> { }
function Badge({ className, variant, ...props }: BadgeProps) { function Badge({ className, variant, ...props }: BadgeProps) {
return ( return (

View File

@@ -35,7 +35,7 @@ const buttonVariants = cva(
export interface ButtonProps export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>, extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> { VariantProps<typeof buttonVariants> {
asChild?: boolean asChild?: boolean
} }

View File

@@ -82,13 +82,13 @@ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
([theme, prefix]) => ` ([theme, prefix]) => `
${prefix} [data-chart=${id}] { ${prefix} [data-chart=${id}] {
${colorConfig ${colorConfig
.map(([key, itemConfig]) => { .map(([key, itemConfig]) => {
const color = const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
itemConfig.color itemConfig.color
return color ? ` --color-${key}: ${color};` : null return color ? ` --color-${key}: ${color};` : null
}) })
.join("\n")} .join("\n")}
} }
` `
) )
@@ -103,13 +103,13 @@ const ChartTooltip = RechartsPrimitive.Tooltip
const ChartTooltipContent = React.forwardRef< const ChartTooltipContent = React.forwardRef<
HTMLDivElement, HTMLDivElement,
React.ComponentProps<typeof RechartsPrimitive.Tooltip> & React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
React.ComponentProps<"div"> & { React.ComponentProps<"div"> & {
hideLabel?: boolean hideLabel?: boolean
hideIndicator?: boolean hideIndicator?: boolean
indicator?: "line" | "dot" | "dashed" indicator?: "line" | "dot" | "dashed"
nameKey?: string nameKey?: string
labelKey?: string labelKey?: string
} }
>( >(
( (
{ {
@@ -259,10 +259,10 @@ const ChartLegend = RechartsPrimitive.Legend
const ChartLegendContent = React.forwardRef< const ChartLegendContent = React.forwardRef<
HTMLDivElement, HTMLDivElement,
React.ComponentProps<"div"> & React.ComponentProps<"div"> &
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & { Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
hideIcon?: boolean hideIcon?: boolean
nameKey?: string nameKey?: string
} }
>( >(
( (
{ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey }, { className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
@@ -326,8 +326,8 @@ function getPayloadConfigFromPayload(
const payloadPayload = const payloadPayload =
"payload" in payload && "payload" in payload &&
typeof payload.payload === "object" && typeof payload.payload === "object" &&
payload.payload !== null payload.payload !== null
? payload.payload ? payload.payload
: undefined : undefined

View File

@@ -21,7 +21,7 @@ const Command = React.forwardRef<
)) ))
Command.displayName = CommandPrimitive.displayName Command.displayName = CommandPrimitive.displayName
interface CommandDialogProps extends DialogProps {} interface CommandDialogProps extends DialogProps { }
const CommandDialog = ({ children, ...props }: CommandDialogProps) => { const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
return ( return (

View File

@@ -11,7 +11,7 @@ const labelVariants = cva(
const Label = React.forwardRef< const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>, React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants> VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<LabelPrimitive.Root <LabelPrimitive.Root
ref={ref} ref={ref}

View File

@@ -31,9 +31,9 @@ const ScrollBar = React.forwardRef<
className={cn( className={cn(
"flex touch-none select-none transition-colors", "flex touch-none select-none transition-colors",
orientation === "vertical" && orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent p-[1px]", "h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" && orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent p-[1px]", "h-2.5 flex-col border-t border-t-transparent p-[1px]",
className className
)} )}
{...props} {...props}

View File

@@ -75,7 +75,7 @@ const SelectContent = React.forwardRef<
className={cn( className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" && position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className className
)} )}
position={position} position={position}
@@ -86,7 +86,7 @@ const SelectContent = React.forwardRef<
className={cn( className={cn(
"p-1", "p-1",
position === "popper" && position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]" "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
)} )}
> >
{children} {children}

View File

@@ -128,4 +128,3 @@ export {
Sheet, SheetClose, Sheet, SheetClose,
SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger
} }

View File

@@ -612,7 +612,7 @@ const SidebarMenuAction = React.forwardRef<
"peer-data-[size=lg]/menu-button:top-2.5", "peer-data-[size=lg]/menu-button:top-2.5",
"group-data-[collapsible=icon]:hidden", "group-data-[collapsible=icon]:hidden",
showOnHover && showOnHover &&
"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0", "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0",
className className
)} )}
{...props} {...props}

View File

@@ -3,7 +3,7 @@ import * as React from "react"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
export interface TextareaProps export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {} extends React.TextareaHTMLAttributes<HTMLTextAreaElement> { }
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>( const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => { ({ className, ...props }, ref) => {

View File

@@ -41,7 +41,7 @@ const toastVariants = cva(
const Toast = React.forwardRef< const Toast = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Root>, React.ElementRef<typeof ToastPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
VariantProps<typeof toastVariants> VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => { >(({ className, variant, ...props }, ref) => {
return ( return (
<ToastPrimitives.Root <ToastPrimitives.Root

View File

@@ -15,7 +15,7 @@ const ToggleGroupContext = React.createContext<
const ToggleGroup = React.forwardRef< const ToggleGroup = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Root>, React.ElementRef<typeof ToggleGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> & React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
VariantProps<typeof toggleVariants> VariantProps<typeof toggleVariants>
>(({ className, variant, size, children, ...props }, ref) => ( >(({ className, variant, size, children, ...props }, ref) => (
<ToggleGroupPrimitive.Root <ToggleGroupPrimitive.Root
ref={ref} ref={ref}
@@ -33,7 +33,7 @@ ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName
const ToggleGroupItem = React.forwardRef< const ToggleGroupItem = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Item>, React.ElementRef<typeof ToggleGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> & React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
VariantProps<typeof toggleVariants> VariantProps<typeof toggleVariants>
>(({ className, children, variant, size, ...props }, ref) => { >(({ className, children, variant, size, ...props }, ref) => {
const context = React.useContext(ToggleGroupContext) const context = React.useContext(ToggleGroupContext)

View File

@@ -29,7 +29,7 @@ const toggleVariants = cva(
const Toggle = React.forwardRef< const Toggle = React.forwardRef<
React.ElementRef<typeof TogglePrimitive.Root>, React.ElementRef<typeof TogglePrimitive.Root>,
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> & React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
VariantProps<typeof toggleVariants> VariantProps<typeof toggleVariants>
>(({ className, variant, size, ...props }, ref) => ( >(({ className, variant, size, ...props }, ref) => (
<TogglePrimitive.Root <TogglePrimitive.Root
ref={ref} ref={ref}

View File

@@ -32,21 +32,21 @@ type ActionType = typeof actionTypes
type Action = type Action =
| { | {
type: ActionType["ADD_TOAST"] type: ActionType["ADD_TOAST"]
toast: ToasterToast toast: ToasterToast
} }
| { | {
type: ActionType["UPDATE_TOAST"] type: ActionType["UPDATE_TOAST"]
toast: Partial<ToasterToast> toast: Partial<ToasterToast>
} }
| { | {
type: ActionType["DISMISS_TOAST"] type: ActionType["DISMISS_TOAST"]
toastId?: ToasterToast["id"] toastId?: ToasterToast["id"]
} }
| { | {
type: ActionType["REMOVE_TOAST"] type: ActionType["REMOVE_TOAST"]
toastId?: ToasterToast["id"] toastId?: ToasterToast["id"]
} }
interface State { interface State {
toasts: ToasterToast[] toasts: ToasterToast[]
@@ -104,9 +104,9 @@ export const reducer = (state: State, action: Action): State => {
toasts: state.toasts.map((t) => toasts: state.toasts.map((t) =>
t.id === toastId || toastId === undefined t.id === toastId || toastId === undefined
? { ? {
...t, ...t,
open: false, open: false,
} }
: t : t
), ),
} }

View File

@@ -1,5 +1,3 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@@ -66,7 +64,9 @@
* { * {
@apply border-border; @apply border-border;
} }
html, body {
html,
body {
@apply bg-background text-foreground; @apply bg-background text-foreground;
height: 100vh; height: 100vh;
width: 100vw; width: 100vw;
@@ -74,12 +74,14 @@
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
body { body {
font-family: 'Inter', system-ui, sans-serif; font-family: 'Inter', system-ui, sans-serif;
} }
#root { #root {
height: 100vh; height: 100vh;
width: 100vw; width: 100vw;
overflow: hidden; overflow: hidden;
} }
} }

View File

@@ -25,8 +25,8 @@ export type HTMLString = string
type ExpandType<T> = unknown extends T type ExpandType<T> = unknown extends T
? T extends unknown ? T extends unknown
? { expand?: unknown } ? { expand?: unknown }
: { expand: T } : { expand: T }
: { expand: T } : { expand: T }
// System fields // System fields

View File

@@ -1,5 +1,5 @@
import { createRoot } from 'react-dom/client' import { createRoot } from 'react-dom/client';
import App from './App.tsx' import App from './App.tsx';
import './index.css' import './index.css';
createRoot(document.getElementById("root")!).render(<App />); createRoot(document.getElementById("root")!).render(<App />);

View File

@@ -7,14 +7,14 @@ import { useNavigate } from 'react-router-dom';
export const RegionPage = () => { export const RegionPage = () => {
const { region } = useParams<{ region: string }>(); const { region } = useParams<{ region: string }>();
const navigate = useNavigate(); const navigate = useNavigate();
if (!region) { if (!region) {
return ( return (
<div className="h-screen w-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 flex items-center justify-center overflow-hidden"> <div className="h-screen w-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 flex items-center justify-center overflow-hidden">
<div className="text-center"> <div className="text-center">
<h1 className="text-4xl font-bold text-white mb-4">Region Not Found</h1> <h1 className="text-4xl font-bold text-white mb-4">Region Not Found</h1>
<p className="text-purple-200 mb-6">The requested region does not exist in our database.</p> <p className="text-purple-200 mb-6">The requested region does not exist in our database.</p>
<Button <Button
onClick={() => navigate('/')} onClick={() => navigate('/')}
className="bg-purple-600 hover:bg-purple-700" className="bg-purple-600 hover:bg-purple-700"
> >
@@ -28,8 +28,8 @@ export const RegionPage = () => {
return ( return (
<div className="h-screen w-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 overflow-hidden"> <div className="h-screen w-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 overflow-hidden">
<RegionMap <RegionMap
regionName={region} regionName={region}
isWormholeRegion={region === "Wormhole"} isWormholeRegion={region === "Wormhole"}
/> />
</div> </div>

View File

@@ -1,7 +1,7 @@
export const getSecurityColor = (security: number): string => { export const getSecurityColor = (security: number): string => {
// Clamp security between -1 and 1 // Clamp security between -1 and 1
const clampedSecurity = Math.max(-1, Math.min(1, security)); const clampedSecurity = Math.max(-1, Math.min(1, security));
// Define color points for specific security values // Define color points for specific security values
const colorPoints = [ const colorPoints = [
{ sec: -1.0, color: [75, 0, 130] }, // Dark purple (same as 0.1) { sec: -1.0, color: [75, 0, 130] }, // Dark purple (same as 0.1)
@@ -31,7 +31,7 @@ export const getSecurityColor = (security: number): string => {
// Calculate the ratio between the two points // Calculate the ratio between the two points
const ratio = (clampedSecurity - lowerPoint.sec) / (upperPoint.sec - lowerPoint.sec); const ratio = (clampedSecurity - lowerPoint.sec) / (upperPoint.sec - lowerPoint.sec);
// Interpolate between the colors // Interpolate between the colors
const red = Math.round(lowerPoint.color[0] + (upperPoint.color[0] - lowerPoint.color[0]) * ratio); const red = Math.round(lowerPoint.color[0] + (upperPoint.color[0] - lowerPoint.color[0]) * ratio);
const green = Math.round(lowerPoint.color[1] + (upperPoint.color[1] - lowerPoint.color[1]) * ratio); const green = Math.round(lowerPoint.color[1] + (upperPoint.color[1] - lowerPoint.color[1]) * ratio);