diff --git a/web/src/authorities/authorities-page.tsx b/web/src/authorities/authorities-page.tsx index b0696af..ec90e7f 100644 --- a/web/src/authorities/authorities-page.tsx +++ b/web/src/authorities/authorities-page.tsx @@ -6,7 +6,9 @@ import type { components } from "../api/schema"; import { useAuthorities, useCreateAuthority } from "../api/queries"; import { LabelEditor } from "../components/label-editor"; import { Button } from "@/components/ui/button"; +import { PageTitle } from "@/components/ui/page-title"; import { AuthorityRow } from "./authority-row"; +import { useDocumentTitle } from "../lib/use-document-title"; type LabelInput = components["schemas"]["LabelInput"]; @@ -26,6 +28,8 @@ export function AuthoritiesPage() { const [labels, setLabels] = useState([]); const [error, setError] = useState(false); + useDocumentTitle(t("nav.authorities")); + if (!isValidKind) return ; const onCreate = (event: FormEvent) => { @@ -45,6 +49,7 @@ export function AuthoritiesPage() { return (
+ {t("nav.authorities")}
{KINDS.map((k) => ( (null); + useDocumentTitle(t("fields.title")); + return ( -
-
- -
-
- setSelected(null)} - /> +
+ {t("fields.title")} +
+
+ +
+
+ setSelected(null)} + /> +
); diff --git a/web/src/objects/object-new-page.tsx b/web/src/objects/object-new-page.tsx index 6f69c3a..4887877 100644 --- a/web/src/objects/object-new-page.tsx +++ b/web/src/objects/object-new-page.tsx @@ -4,6 +4,8 @@ import { useTranslation } from "react-i18next"; import { ObjectForm, type ObjectFormValues } from "./object-form"; import { useCreateObject, useSetFields, FieldRejection } from "../api/queries"; +import { useDocumentTitle } from "../lib/use-document-title"; +import { PageTitle } from "@/components/ui/page-title"; export function ObjectNewPage() { const { t } = useTranslation(); @@ -12,6 +14,8 @@ export function ObjectNewPage() { const setFields = useSetFields(); const [error, setError] = useState(null); + useDocumentTitle(t("objects.new")); + const onSubmit = async (values: ObjectFormValues) => { setError(null); @@ -44,6 +48,7 @@ export function ObjectNewPage() { return (
+ {t("objects.new")} { vi.restoreAllMocks(); }); +test("renders the page heading and sets the document title", async () => { + setViewport(true); + renderApp(tree(), { route: "/objects" }); + + expect( + await screen.findByRole("heading", { level: 1, name: /objects/i }), + ).toBeInTheDocument(); + await waitFor(() => expect(document.title).toMatch(/objects \| /i)); +}); + test("the table is the landing view; no detail panel until a row is opened", async () => { setViewport(true); renderApp(tree(), { route: "/objects" }); diff --git a/web/src/objects/objects-page.tsx b/web/src/objects/objects-page.tsx index e37de63..d3f490c 100644 --- a/web/src/objects/objects-page.tsx +++ b/web/src/objects/objects-page.tsx @@ -5,6 +5,8 @@ import { X } from "lucide-react"; import { ObjectsTable } from "./objects-table"; import { useMediaQuery } from "../lib/use-media-query"; +import { useDocumentTitle } from "../lib/use-document-title"; +import { PageTitle } from "@/components/ui/page-title"; const ObjectDetailDrawer = lazy(() => import("./object-detail-drawer").then((m) => ({ default: m.ObjectDetailDrawer })), @@ -23,11 +25,16 @@ export function ObjectsPage() { const open = Boolean(detailMatch ?? editMatch); const isWide = useMediaQuery("(min-width: 1024px)"); + useDocumentTitle(t("nav.objects")); + const closeDetail = () => navigate(`/objects?${searchParams}`); const table = ( -
- +
+ {t("nav.objects")} +
+ +
); diff --git a/web/src/search/search-page.tsx b/web/src/search/search-page.tsx index 41ac0ed..a14706a 100644 --- a/web/src/search/search-page.tsx +++ b/web/src/search/search-page.tsx @@ -1,15 +1,25 @@ import { Outlet } from "react-router-dom"; +import { useTranslation } from "react-i18next"; import { SearchPanel } from "./search-panel"; +import { useDocumentTitle } from "../lib/use-document-title"; +import { PageTitle } from "@/components/ui/page-title"; export function SearchPage() { + const { t } = useTranslation(); + + useDocumentTitle(t("nav.search")); + return ( -
-
- -
-
- +
+ {t("nav.search")} +
+
+ +
+
+ +
); diff --git a/web/src/vocab/vocabularies-page.tsx b/web/src/vocab/vocabularies-page.tsx index ac24fcc..64e06d5 100644 --- a/web/src/vocab/vocabularies-page.tsx +++ b/web/src/vocab/vocabularies-page.tsx @@ -1,15 +1,25 @@ import { Outlet } from "react-router-dom"; +import { useTranslation } from "react-i18next"; import { VocabularyList } from "./vocabulary-list"; +import { useDocumentTitle } from "../lib/use-document-title"; +import { PageTitle } from "@/components/ui/page-title"; export function VocabulariesPage() { + const { t } = useTranslation(); + + useDocumentTitle(t("nav.vocabularies")); + return ( -
-
- -
-
- +
+ {t("nav.vocabularies")} +
+
+ +
+
+ +
);