Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explorer v2 [WIP] #137

Open
wants to merge 67 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
b5b07ad
Start new navbar
mbthiery Jul 10, 2024
ca05fb7
More nav
mbthiery Jul 15, 2024
e74f760
Add nav control
mbthiery Jul 15, 2024
969f1a3
Add connection power + settings overlays
mbthiery Jul 15, 2024
fead644
Use heroicons
mbthiery Jul 15, 2024
8f1a043
Add settings trigger
mbthiery Jul 16, 2024
ad5d07d
Update icons
mbthiery Jul 16, 2024
f93a8f1
Update HotspotProviders
mbthiery Jul 18, 2024
6fd59a2
Update ThemeToggle
mbthiery Jul 18, 2024
96f1e66
Update search
mbthiery Jul 22, 2024
451ec35
Start hotspot details
mbthiery Jul 23, 2024
735f023
Setup hotspot detail pills
mbthiery Jul 23, 2024
9970c7f
Add RSSI Coverage
mbthiery Jul 24, 2024
5e781e1
RSSI tweaks
mbthiery Jul 25, 2024
6b8d668
Overflow + hotspots list
mbthiery Jul 25, 2024
230613b
Make pills consistent
mbthiery Jul 26, 2024
47c2c55
Make shared InfoWrapper
mbthiery Jul 26, 2024
8843b4e
Make shared InfoCard
mbthiery Jul 26, 2024
8ecae3a
Add Insights + ConnectedDevices details
mbthiery Jul 29, 2024
c667c9b
Add TechnicalInfo details
mbthiery Jul 29, 2024
5343403
Setup explorer trigger
mbthiery Jul 29, 2024
a54c3fa
Refactor SettingsTrigger with Overlay
mbthiery Jul 29, 2024
e1925d8
Make explorer options re-usable
mbthiery Jul 30, 2024
4541ba9
Blur backgrounds
mbthiery Jul 31, 2024
bec47e1
Fix nested blur
mbthiery Aug 1, 2024
39faa2c
Add DM Sans
mbthiery Aug 1, 2024
65563ad
Add public alias
mbthiery Aug 1, 2024
925624c
Add hover stats + blur more
mbthiery Aug 2, 2024
de4c930
Minor tweaks + geometricPrecision
mbthiery Aug 2, 2024
2a0b3d7
Fix hotspot capitalization + fix MapZoom hover + remove stats underline
mbthiery Aug 2, 2024
52b5d37
Tweak nav selector styling
mbthiery Aug 2, 2024
6ea6376
Fix spacing for hex info + connected devices button + info wrapper he…
mbthiery Aug 2, 2024
9c8d5a3
Fix colors/opacity
mbthiery Aug 2, 2024
e761676
Show preferred explorer
mbthiery Aug 5, 2024
10db43a
Add pills to map options
mbthiery Aug 5, 2024
741667f
Make hotspot provider order consistent
mbthiery Aug 5, 2024
d275477
Tweak scrollbar display
mbthiery Aug 5, 2024
5e2df32
Fix RssiPill circle + add Kuzco logo
mbthiery Aug 5, 2024
6de1388
Add accessibility to hotspots list
mbthiery Aug 5, 2024
941556e
Add hover states to nav + map tools
mbthiery Aug 8, 2024
a9cfca0
Restyle search
mbthiery Aug 8, 2024
e384839
Improve scrollbar styling
mbthiery Aug 8, 2024
61448d6
Hover styling and other bits and bobs
mbthiery Aug 9, 2024
958446f
Restyle hotspot detail infocards
mbthiery Aug 9, 2024
1642b6a
Tweak ExplorerOptions hover
mbthiery Aug 9, 2024
db2eaa6
Further tweaks on explorer selection
mbthiery Aug 9, 2024
3f94400
Add shared RadioCircles
mbthiery Aug 9, 2024
b20a211
Add hover states to settings
mbthiery Aug 9, 2024
c8bb8ff
Remove redundant styles
mbthiery Aug 9, 2024
ab004fa
Fix selector offset
mbthiery Aug 9, 2024
e099002
Position nav + mapzoom + settings for mobile
mbthiery Aug 12, 2024
842aa60
Only one selector open at a time
mbthiery Aug 12, 2024
3377022
Only open one card details at a time
mbthiery Aug 12, 2024
f40bd63
Restyle hotspot details for mobile
mbthiery Aug 16, 2024
209313e
Only show active detail
mbthiery Aug 16, 2024
614e7f1
Mobile friendly theme + provider overlays
mbthiery Aug 16, 2024
92f6b0d
Add hex details tabs + fix back nav on hotspot details
mbthiery Aug 16, 2024
259ea5b
Conditionally render area info
mbthiery Aug 19, 2024
da59680
Fix background blur + dividers
mbthiery Aug 19, 2024
06ae4e0
Fix font sizes + resize info wrapper button
mbthiery Aug 19, 2024
1205185
Rework Settings X button + Connection power position
mbthiery Aug 19, 2024
bdcd2a8
Update hex icon
mbthiery Aug 19, 2024
d15b014
Design tweaks
mbthiery Aug 21, 2024
359f8f2
Fix InfoWrapper blur
mbthiery Aug 23, 2024
ba70076
Remove stray divider
mbthiery Aug 23, 2024
8ecff4b
Bits and bobs post-design call
mbthiery Aug 26, 2024
d345d17
Short circuit conditional insert logic for review apps
mbthiery Aug 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/connected-devices.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/connected-dots.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/hotspot-waves.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/hotspot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/kuzco-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/latitude.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/longitude.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/tech-info.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/app/layout.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.overall {
text-rendering: geometricPrecision;
}
18 changes: 16 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import { GAScript } from "@/components/GAScript"
import { GATracker } from "@/components/GATracker"
import { Header } from "@/components/Header"
import { HotspotsMap } from "@/components/HotspotsMap"
import { Providers } from "@/components/Providers"
import "@/styles/tailwind.css"
import "focus-visible"
import { DM_Sans } from "next/font/google"
import Head from "next/head"
import { Suspense } from "react"
import "react-tooltip/dist/react-tooltip.css"
import styles from "./layout.module.css"
import { HotspotsMap } from "./new/HotspotsMap"
import { Nav } from "./new/Nav/Nav"

const dm_sans = DM_Sans({
subsets: ["latin"],
display: "swap",
variable: "--font-dm-sans",
})

export const metadata = {
manifest: "/manifest.json",
Expand Down Expand Up @@ -55,7 +64,11 @@ export default function RootLayout({
children: React.ReactNode
}) {
return (
<html lang="en" suppressHydrationWarning>
<html
lang="en"
suppressHydrationWarning
className={`${dm_sans.variable} ${styles.overall}`}
>
<Head>
<link
rel="preconnect"
Expand All @@ -81,6 +94,7 @@ export default function RootLayout({
<GATracker />
</Suspense>
<Header />
<Nav />
<HotspotsMap>{children}</HotspotsMap>
</Providers>
</body>
Expand Down
29 changes: 29 additions & 0 deletions src/app/new/HotspotsMap/ConnectionPower.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { RssiPill } from "@/components/shared/RssiPill"
import clsx from "clsx"

export const ConnectionPower = () => {
return (
<div
className={clsx(
"absolute bottom-4 right-3 justify-center sm:flex",
"sm:bottom-6 sm:right-6 sm:w-auto sm:justify-end"
)}
>
<div className="flex gap-4 rounded-xl bg-[#131313]/60 px-3 py-3 font-sans backdrop-blur">
<p className="text-sm text-white opacity-75">Signal Strength</p>
<div className="flex items-center gap-2">
<RssiPill strength="strong" />
<p className="text-sm text-white opacity-75">High</p>
</div>
<div className="flex items-center gap-2">
<RssiPill strength="medium" />
<p className="text-sm text-white opacity-75">Medium</p>
</div>
<div className="flex items-center gap-2">
<RssiPill strength="low" />
<p className="text-sm text-white opacity-75">Low</p>
</div>
</div>
</div>
)
}
68 changes: 68 additions & 0 deletions src/app/new/HotspotsMap/HexHotspotItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"use client"

import { usePreferences } from "@/context/usePreferences"
import animalHash from "angry-purple-tiger"
import Link from "next/link"
import { gaEvent } from "../GATracker"
import { HeliumIotIcon } from "../icons/HeliumIotIcon"
import { HeliumMobileIcon } from "../icons/HeliumMobileIcon"
import { Hotspot } from "./HexHotspots"

type HexHotSpotItemProps = {
hotspot: Hotspot
}

export const HexHotSpotItem = ({ hotspot }: HexHotSpotItemProps) => {
const { provider } = usePreferences()

const hotspotName = animalHash(hotspot.hotspot_id)
const hasSmallCells = hotspot.cells.length > 0
const Avatar = hasSmallCells ? HeliumMobileIcon : HeliumIotIcon
const subtitle = hasSmallCells
? `${hotspot.cells.length} small cell${
hotspot.cells.length === 1 ? "" : "s"
}`
: "IoT Hotspot"

return (
<li key={hotspot.hotspot_id}>
<div className="group relative flex items-center px-2 py-3">
<Link
href={
!provider
? `/preferences?redirect=${hotspot.hotspot_id}`
: provider.getUrl(hotspot.hotspot_id)
}
className="-m-1 block flex-1 p-1"
target={!!provider ? "_" : "_self"}
onClick={() => {
if (!!provider) {
gaEvent({
action: "outbound_click",
event: {
description: provider.label,
},
})
}
}}
>
<div
className="absolute inset-0 group-hover:bg-zinc-300/30 dark:group-hover:bg-zinc-700/30"
aria-hidden="true"
/>
<div className="relative flex min-w-0 flex-1 items-center gap-4">
<Avatar className="inline-block h-8 w-8 flex-shrink-0" />
<div className="truncate">
<p className="truncate text-sm font-medium leading-5 text-gray-900 dark:text-zinc-100">
{hotspotName}
</p>
<p className="truncate text-xs text-gray-600 dark:text-zinc-300">
{subtitle}
</p>
</div>
</div>
</Link>
</div>
</li>
)
}
113 changes: 113 additions & 0 deletions src/app/new/HotspotsMap/HexHotspots.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Tooltip } from "@/app/stats/components/Tooltip"
import { PreferencesProvider } from "@/context/usePreferences"
import clsx from "clsx"
import { HexHotSpotItem } from "./HexHotspotItem"

interface SmallCell {
cell_id: string
}

export interface Hotspot {
hotspot_id: string
active: boolean
cells: SmallCell[]
}

interface HexData {
hex: string
resolution: number
hotspots: Hotspot[]
}

const RECENT = "recently rewarded"
const NOT_RECENT = "not recently rewarded"

const TOOLTIP_DESCRIPTIONS = {
[RECENT]: "A Hotspot that has received rewards in the past 30 days.",
[NOT_RECENT]:
"A Hotspot that has not received rewards in the past 30 days. Such a hotstop is most likely offline. It is also possible for it to be online but not rewarded if it is not transmitting data, not participating in PoC, or only recently online.",
}

function getGroupedHotspots(hotspots: Hotspot[]) {
const groupedHotspots: {
[RECENT]: Hotspot[]
[NOT_RECENT]: Hotspot[]
} = {
[RECENT]: [],
[NOT_RECENT]: [],
}

hotspots.forEach((hotspot) => {
const group = hotspot.active ? RECENT : NOT_RECENT
groupedHotspots[group].push(hotspot)
})

return groupedHotspots
}

export async function HexHotspots({ hexId }: { hexId: string }) {
const { hotspots } = (await fetch(
`${process.env.NEXT_PUBLIC_HOTSPOTTY_EXPLORER_API_URL}/hex/${hexId}`,
{
headers: {
Authorization: `bearer ${process.env.NEXT_PUBLIC_HOTSPOTTY_EXPLORER_API_TOKEN}`,
},
}
).then((res) => res.json())) as HexData

const groupedList = getGroupedHotspots(hotspots)

if (hotspots.length === 0) {
return (
<div className="mb-2 text-sm font-medium text-gray-900 dark:text-zinc-200">
This hex contains no Hotspots.
</div>
)
}

return (
<div className="relative flex-1 overflow-y-auto">
{(Object.keys(groupedList) as Array<keyof typeof groupedList>).map(
(group) => {
if (groupedList[group].length === 0) return
return (
<div key={group}>
<div
className={clsx(
"sticky top-0 z-10 flex items-center justify-between rounded-lg px-2.5 py-1 text-sm font-medium",
"bg-zinc-300/80 text-gray-700",
"dark:bg-zinc-500/50 dark:text-white"
)}
>
<div className="flex gap-2">
<span className="capitalize">{group}</span>
<Tooltip
id={group}
description={TOOLTIP_DESCRIPTIONS[group]}
width="tiny"
/>
</div>
<span className="ml-2 text-xs font-normal">
{groupedList[group].length} Hotspots
</span>
</div>
<PreferencesProvider>
<ul
role="list"
className="z-0 flex-1 divide-y divide-gray-200 overflow-y-auto dark:divide-white/10"
>
{groupedList[group].map((hotspot) => (
<HexHotSpotItem
key={hotspot.hotspot_id}
hotspot={hotspot}
/>
))}
</ul>
</PreferencesProvider>
</div>
)
}
)}
</div>
)
}
39 changes: 39 additions & 0 deletions src/app/new/HotspotsMap/LoadingHexHotspots.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import clsx from "clsx"

export function LoadingHexHotspots({ count }: { count: number }) {
return (
<div>
<div
className={clsx(
"flex items-center justify-between rounded-lg px-6 py-1 text-sm font-medium",
"bg-zinc-300/80 text-gray-700",
"dark:bg-zinc-500/50 dark:text-white"
)}
>
<span className="capitalize">Active</span>
</div>
<ul
role="list"
className="flex-1 divide-y divide-gray-200 overflow-y-auto dark:divide-white/10"
>
{[...Array(count).keys()].map((i) => (
<li key={i}>
<div className="group relative flex animate-pulse items-center px-5 py-6">
<div className="-m-1 block flex-1 p-1">
<div className="relative flex min-w-0 flex-1 items-center gap-4">
<span className="relative inline-block flex-shrink-0">
<div className="h-10 w-10 rounded-full bg-gray-500 dark:bg-gray-700" />
</span>
<div className="flex-1 space-y-6 py-1">
<div className="h-2 rounded bg-gray-500 dark:bg-gray-700" />
<div className="h-2 rounded bg-gray-500 dark:bg-gray-700" />
</div>
</div>
</div>
</div>
</li>
))}
</ul>
</div>
)
}
64 changes: 64 additions & 0 deletions src/app/new/HotspotsMap/MapZoom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { MinusIcon, PlusIcon } from "@heroicons/react/24/outline"
import clsx from "clsx"
import { useEffect, useState } from "react"
import { useMap } from "react-map-gl"
import { MAX_MAP_ZOOM, MIN_MAP_ZOOM } from "./utils"

export const MapZoom = () => {
const map = useMap()
const [_currentZoom, setCurrentZoom] = useState(map.current?.getZoom())
const zoom = map.current?.getZoom()
useEffect(() => {
const interval = setInterval(() => {
setCurrentZoom(map.current?.getZoom())
}, 250)
return () => clearInterval(interval)
}, [map, setCurrentZoom])

const isZoomInDisabled = zoom === MAX_MAP_ZOOM
const isZoomOutDisabled = zoom === MIN_MAP_ZOOM

return (
<div
className={clsx(
"absolute flex gap-2",
"bottom-[72px] right-4",
"sm:right-6 sm:top-24 sm:flex-col",
"sm:flex"
)}
>
<button
className={clsx(
"group flex h-10 w-10 items-center justify-center rounded-xl bg-[#131313]/60 backdrop-blur"
)}
disabled={isZoomInDisabled}
onClick={() => map.current?.zoomIn()}
>
<PlusIcon
className={clsx(
"h-8 w-8 rounded-lg stroke-[#DBE0E6] p-1.5 opacity-75 transition group-disabled:stroke-[#64686D]",
!isZoomInDisabled &&
"group-hover:bg-[#8A8A8A]/20 group-hover:stroke-white group-hover:opacity-100",
isZoomOutDisabled && "cursor-not-allowed"
)}
/>
</button>
<button
className={clsx(
"group flex h-10 w-10 items-center justify-center rounded-xl bg-[#131313]/60 backdrop-blur"
)}
disabled={isZoomOutDisabled}
onClick={() => map.current?.zoomOut()}
>
<MinusIcon
className={clsx(
"h-8 w-8 rounded-lg stroke-[#DBE0E6] p-1.5 opacity-75 transition group-disabled:stroke-[#64686D]",
!isZoomOutDisabled &&
"group-hover:bg-[#8A8A8A]/20 group-hover:stroke-white group-hover:opacity-100",
isZoomOutDisabled && "cursor-not-allowed"
)}
/>
</button>
</div>
)
}
Loading
Loading