feat(admin): add search with submit and safe-area layout
Add submit-based search to admin books page and switch borrows search from debounced to submit-based for consistency. Update layout headers and nav bars to respect mobile safe-area insets via CSS custom properties.
This commit is contained in:
+35
-1
@@ -1,6 +1,40 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="en" class="no-select">
|
||||
<head>
|
||||
<script>
|
||||
if (window.__TAURI_INTERNALS__) {
|
||||
function allowsSelection(el) {
|
||||
let cur = el
|
||||
while (cur) {
|
||||
if (
|
||||
cur.tagName === "INPUT" ||
|
||||
cur.tagName === "TEXTAREA" ||
|
||||
cur.hasAttribute("data-selectable")
|
||||
)
|
||||
return true
|
||||
cur = cur.parentElement
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
document.addEventListener("selectstart", (e) => {
|
||||
if (!allowsSelection(e.target)) e.preventDefault()
|
||||
})
|
||||
|
||||
document.addEventListener("selectionchange", () => {
|
||||
const sel = window.getSelection()
|
||||
if (!sel || sel.isCollapsed) return
|
||||
const node = sel.anchorNode
|
||||
if (!node) return
|
||||
const el = node.nodeType === 3 ? node.parentElement : node
|
||||
if (el && !allowsSelection(el)) {
|
||||
sel.removeAllRanges()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
document.documentElement.classList.remove("no-select")
|
||||
}
|
||||
</script>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog"
|
||||
import { useAdminBooks, useAdminSearchBooks, useAddBook, useUpdateBook, useUpdateStock, useDeleteBook, useAdminBorrowBook } from "./hooks"
|
||||
import { usePlatform } from "@/hooks/usePlatform"
|
||||
import { useIsMobile } from "@/hooks/useIsMobile"
|
||||
import type { Book } from "@/types/api"
|
||||
import { getErrorMessage } from "@/lib/errors"
|
||||
@@ -33,9 +32,8 @@ interface BorrowDialog { open: boolean; book: Book }
|
||||
const addInitial: AddDialog = { open: false }
|
||||
|
||||
export default function AdminBooksPage() {
|
||||
const platform = usePlatform()
|
||||
const isMobile = useIsMobile()
|
||||
const sel = platform === "web" ? ({ "data-selectable": true } as const) : ({} as const)
|
||||
const sel = { "data-selectable": true } as const
|
||||
|
||||
const [searchText, setSearchText] = useState("")
|
||||
const [submitted, setSubmitted] = useState("")
|
||||
|
||||
@@ -17,16 +17,14 @@ import {
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog"
|
||||
import { useAdminBorrows, useSearchBorrows, useAdminReturnBook } from "./hooks"
|
||||
import { usePlatform } from "@/hooks/usePlatform"
|
||||
import { useIsMobile } from "@/hooks/useIsMobile"
|
||||
import { formatDateTime } from "@/lib/formatters"
|
||||
import { getErrorMessage } from "@/lib/errors"
|
||||
import type { BorrowInfoVo } from "@/types/api"
|
||||
|
||||
export default function AdminBorrowsPage() {
|
||||
const platform = usePlatform()
|
||||
const isMobile = useIsMobile()
|
||||
const sel = platform === "web" ? ({ "data-selectable": true } as const) : ({} as const)
|
||||
const sel = { "data-selectable": true } as const
|
||||
|
||||
const [searchText, setSearchText] = useState("")
|
||||
const [submitted, setSubmitted] = useState("")
|
||||
|
||||
@@ -7,16 +7,14 @@ import { Input } from "@/components/ui/input"
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
import { useBooks, useSearchBooks, useBorrowBook } from "./hooks"
|
||||
import { useAuthStore } from "@/store/authStore"
|
||||
import { usePlatform } from "@/hooks/usePlatform"
|
||||
import { useIsMobile } from "@/hooks/useIsMobile"
|
||||
import { getErrorMessage } from "@/lib/errors"
|
||||
|
||||
export default function BooksPage() {
|
||||
const borrow = useBorrowBook()
|
||||
const token = useAuthStore((s) => s.token)
|
||||
const platform = usePlatform()
|
||||
const isMobile = useIsMobile()
|
||||
const sel = platform === "web" ? ({ "data-selectable": true } as const) : ({} as const)
|
||||
const sel = { "data-selectable": true } as const
|
||||
|
||||
const [searchText, setSearchText] = useState("")
|
||||
const [submitted, setSubmitted] = useState("")
|
||||
|
||||
@@ -8,15 +8,13 @@ import { Input } from "@/components/ui/input"
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
import { useMyBorrows, useSearchMyBorrows, useReturnBook } from "./hooks"
|
||||
import { formatDateTime } from "@/lib/formatters"
|
||||
import { usePlatform } from "@/hooks/usePlatform"
|
||||
import { useIsMobile } from "@/hooks/useIsMobile"
|
||||
import { getErrorMessage } from "@/lib/errors"
|
||||
|
||||
export default function MyBorrowsPage() {
|
||||
const returnBook = useReturnBook()
|
||||
const platform = usePlatform()
|
||||
const isMobile = useIsMobile()
|
||||
const sel = platform === "web" ? ({ "data-selectable": true } as const) : ({} as const)
|
||||
const sel = { "data-selectable": true } as const
|
||||
|
||||
const [searchText, setSearchText] = useState("")
|
||||
const [submitted, setSubmitted] = useState("")
|
||||
|
||||
@@ -8,12 +8,6 @@ function isTauri(): boolean {
|
||||
return !!(window as unknown as Record<string, unknown>).__TAURI_INTERNALS__
|
||||
}
|
||||
|
||||
// Default to safe: add no-select immediately, remove only if definitely web
|
||||
document.documentElement.classList.add("no-select")
|
||||
if (!isTauri()) {
|
||||
document.documentElement.classList.remove("no-select")
|
||||
}
|
||||
|
||||
export function PlatformProvider({ children }: { children: ReactNode }) {
|
||||
const [platform, setPlatform] = useState<Platform>(isTauri() ? "desktop" : "web")
|
||||
|
||||
|
||||
@@ -140,11 +140,14 @@ html.mobile body {
|
||||
}
|
||||
|
||||
html.no-select * {
|
||||
-webkit-user-select: none !important;
|
||||
user-select: none !important;
|
||||
}
|
||||
|
||||
html.no-select input,
|
||||
html.no-select textarea,
|
||||
html.no-select [data-selectable] {
|
||||
-webkit-user-select: text !important;
|
||||
user-select: text !important;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user