mirror of
https://github.com/zvx-echo6/navi.git
synced 2026-05-20 22:54:42 +02:00
Add contacts/phone book UI with search integration
New components: - ContactModal.jsx: Save/edit overlay with form fields and soft delete - ContactList.jsx: Contacts tab with filter, create, and tap-to-navigate Modified: - store.js: Add contacts slice (contacts, activeTab, editingContact) - api.js: Add contacts API functions (fetch, create, update, delete, nearby) - config.js: Add has_contacts fallback flag - Panel.jsx: Routes/Contacts tab bar (only when has_contacts enabled) - PlaceDetail.jsx: Save button opens ContactModal, proximity annotation - SearchBar.jsx: Prepend matching contacts before Photon results - App.jsx: Render ContactModal at top level - index.css: Modal overlay, tab bar, contact list item styles Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
03e9780834
commit
3ce860c1e8
10 changed files with 1087 additions and 66 deletions
|
|
@ -1,10 +1,12 @@
|
|||
import { useRef, useCallback, useEffect, useState } from 'react'
|
||||
import { Sun, Moon } from 'lucide-react'
|
||||
import { useStore } from '../store'
|
||||
import { hasFeature } from '../config'
|
||||
import SearchBar from './SearchBar'
|
||||
import StopList from './StopList'
|
||||
import ModeSelector from './ModeSelector'
|
||||
import ManeuverList from './ManeuverList'
|
||||
import ContactList from './ContactList'
|
||||
import { requestOptimizedRoute } from '../api'
|
||||
|
||||
export default function Panel({ onManeuverClick }) {
|
||||
|
|
@ -24,6 +26,8 @@ export default function Panel({ onManeuverClick }) {
|
|||
const setThemeOverride = useStore((s) => s.setThemeOverride)
|
||||
const gpsOrigin = useStore((s) => s.gpsOrigin)
|
||||
const geoPermission = useStore((s) => s.geoPermission)
|
||||
const activeTab = useStore((s) => s.activeTab)
|
||||
const setActiveTab = useStore((s) => s.setActiveTab)
|
||||
|
||||
const [isMobile, setIsMobile] = useState(false)
|
||||
const [optimizing, setOptimizing] = useState(false)
|
||||
|
|
@ -31,6 +35,8 @@ export default function Panel({ onManeuverClick }) {
|
|||
const dragStartY = useRef(0)
|
||||
const dragStartState = useRef('half')
|
||||
|
||||
const showContacts = hasFeature('has_contacts')
|
||||
|
||||
// Responsive detection
|
||||
useEffect(() => {
|
||||
const check = () => setIsMobile(window.innerWidth < 768)
|
||||
|
|
@ -60,7 +66,6 @@ export default function Panel({ onManeuverClick }) {
|
|||
}
|
||||
const data = await requestOptimizedRoute(locations, mode)
|
||||
if (data.trip) {
|
||||
// If GPS origin was prepended, skip it from the result waypoints
|
||||
const wpOrder = hasGpsOrigin && userLocation
|
||||
? (data.trip.locations || []).slice(1)
|
||||
: data.trip.locations
|
||||
|
|
@ -116,7 +121,7 @@ export default function Panel({ onManeuverClick }) {
|
|||
|
||||
const showOptimize = effectiveCount >= 3
|
||||
|
||||
const content = (
|
||||
const routesContent = (
|
||||
<>
|
||||
<SearchBar />
|
||||
|
||||
|
|
@ -153,6 +158,29 @@ export default function Panel({ onManeuverClick }) {
|
|||
</>
|
||||
)
|
||||
|
||||
const content = (
|
||||
<>
|
||||
{showContacts && (
|
||||
<div className="navi-tab-bar mb-3">
|
||||
<button
|
||||
className={`navi-tab ${activeTab === 'routes' ? 'navi-tab-active' : ''}`}
|
||||
onClick={() => setActiveTab('routes')}
|
||||
>
|
||||
Routes
|
||||
</button>
|
||||
<button
|
||||
className={`navi-tab ${activeTab === 'contacts' ? 'navi-tab-active' : ''}`}
|
||||
onClick={() => setActiveTab('contacts')}
|
||||
>
|
||||
Contacts
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(!showContacts || activeTab === 'routes') ? routesContent : <ContactList />}
|
||||
</>
|
||||
)
|
||||
|
||||
const header = (
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h1 className="text-md font-semibold" style={{ color: 'var(--accent)' }}>Navi</h1>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue