+ {beforeHeaderContent && (
+
+ {beforeHeaderContent}
+
+ )}
+ {isNotDefined(blockingContent) && showPageContainer && (
+
+ )}
+ {isNotDefined(blockingContent) && (
+
+
+ { children }
+
+
+ )}
+
+ );
+}
+
+export default Page;
diff --git a/app/components/Page/styles.module.css b/app/components/Page/styles.module.css
new file mode 100644
index 0000000..bfd24da
--- /dev/null
+++ b/app/components/Page/styles.module.css
@@ -0,0 +1,29 @@
+.page {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+
+ .machine-translation-warning {
+ background-color: var(--go-ui-color-warning);
+ padding: var(--go-ui-spacing-sm);
+ text-align: center;
+ color: var(--go-ui-color-white);
+ }
+
+ .page-header {
+ background-color: var(--go-ui-color-background);
+ }
+
+ .main-section-container {
+ flex-grow: 1;
+ background-color: var(--go-ui-color-white);
+
+ &.with-background-color {
+ background-color: var(--go-ui-color-background);
+ }
+
+ .main-section {
+ padding: var(--go-ui-spacing-4xl) var(--go-ui-spacing-lg);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/components/PdfViewer/index.tsx b/app/components/PdfViewer/index.tsx
new file mode 100644
index 0000000..bcdf7c4
--- /dev/null
+++ b/app/components/PdfViewer/index.tsx
@@ -0,0 +1,75 @@
+import 'react-pdf/dist/Page/AnnotationLayer.css';
+import 'react-pdf/dist/Page/TextLayer.css';
+
+import {
+ useCallback,
+ useState,
+} from 'react';
+import {
+ Document,
+ Page as PdfPage,
+ pdfjs,
+} from 'react-pdf';
+
+pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
+
+interface PdfViewerProps {
+ file: string;
+ loadingMessage?: React.ReactNode;
+ errorMessage?: React.ReactNode;
+}
+
+function PdfViewer({
+ file,
+ loadingMessage = Failed to load PDF.
,
+}: PdfViewerProps) {
+ const [numPages, setNumPages] = useState