Adds first version of the app. Local storage only.
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import { useRef } from 'react'
|
||||
import { downloadProjectFile, readProjectFile, ProjectImportError } from '../../data/exportImport'
|
||||
import { useProjectStore } from '../../state/projectStore'
|
||||
|
||||
export default function TopBar() {
|
||||
const project = useProjectStore((s) => s.project)
|
||||
const renameProject = useProjectStore((s) => s.renameProject)
|
||||
const newProject = useProjectStore((s) => s.newProject)
|
||||
const importProject = useProjectStore((s) => s.importProject)
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
const handleNewProject = () => {
|
||||
if (project.devices.length > 0 || project.connections.length > 0) {
|
||||
const confirmed = window.confirm('Start a new project? Unsaved changes to the current one will be lost (unless exported).')
|
||||
if (!confirmed) return
|
||||
}
|
||||
newProject()
|
||||
}
|
||||
|
||||
const handleExport = () => downloadProjectFile(project)
|
||||
|
||||
const handleImportClick = () => fileInputRef.current?.click()
|
||||
|
||||
const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0]
|
||||
event.target.value = ''
|
||||
if (!file) return
|
||||
try {
|
||||
const imported = await readProjectFile(file)
|
||||
importProject(imported)
|
||||
} catch (err) {
|
||||
const message = err instanceof ProjectImportError ? err.message : 'Could not read that file.'
|
||||
window.alert(`Import failed: ${message}`)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<header className="flex h-12 shrink-0 items-center justify-between border-b border-slate-200 bg-white px-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-semibold text-indigo-700">AV Planner</span>
|
||||
<input
|
||||
value={project.name}
|
||||
onChange={(e) => renameProject(e.target.value)}
|
||||
className="rounded border border-transparent px-2 py-1 text-sm text-slate-700 hover:border-slate-200 focus:border-slate-300 focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<button onClick={handleNewProject} className="rounded px-2.5 py-1.5 text-xs text-slate-600 hover:bg-slate-100">
|
||||
New
|
||||
</button>
|
||||
<button onClick={handleImportClick} className="rounded px-2.5 py-1.5 text-xs text-slate-600 hover:bg-slate-100">
|
||||
Import
|
||||
</button>
|
||||
<input ref={fileInputRef} type="file" accept="application/json,.json" className="hidden" onChange={handleFileChange} />
|
||||
<button
|
||||
onClick={handleExport}
|
||||
className="rounded bg-indigo-600 px-2.5 py-1.5 text-xs font-medium text-white hover:bg-indigo-500"
|
||||
>
|
||||
Export
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user