diff --git a/src/components/Settings/Overlay.tsx b/src/components/Settings/Overlay.tsx
new file mode 100644
index 0000000..23aa0c4
--- /dev/null
+++ b/src/components/Settings/Overlay.tsx
@@ -0,0 +1,973 @@
+import {
+ batch,
+ Component,
+ FlowComponent,
+ For,
+ Show,
+ useContext,
+ JSX,
+ startTransition,
+ createMemo,
+ onMount,
+ onCleanup,
+} from "solid-js";
+import { createStore, reconcile, unwrap } from "solid-js/store";
+import { format, fromUnixTime } from "date-fns";
+import z from "myzod";
+import Big from "big.js";
+import { generate } from "node-iso11649";
+import { customAlphabet } from "nanoid";
+
+import createAccordion from "../Accordion";
+import { Checkbox, TextArea, TextInput, UnixDateInput } from "../Form";
+import { autoAnimate } from "~/directives/autoAnimate";
+import {
+ LocalStoreContext,
+ localStoreSchema,
+ POSITION_TYPE_AGILE,
+ POSITION_TYPE_QUANTITY,
+ PRINT_TYPE_CONFIRMATION,
+ PRINT_TYPE_INVOICE,
+ PRINT_TYPE_OFFER,
+ StoreContext,
+ storeSchema,
+ UiStoreContext,
+} from "~/stores";
+import { AddressData, isStructuredAddress } from "../Address";
+import PositionsIcon from "~icons/carbon/show-data-cards";
+import YouIcon from "~icons/carbon/face-wink";
+import DesignIcon from "~icons/carbon/paint-brush";
+import PrinterIcon from "~icons/carbon/printer";
+import ProjectIcon from "~icons/carbon/product";
+import DownloadIcon from "~icons/carbon/download";
+import LoadIcon from "~icons/carbon/folder";
+import LoadingSpinnerIcon from "~icons/icomoon-free/spinner9";
+import ErrorIcon from "~icons/carbon/error";
+import SuccessIcon from "~icons/carbon/checkmark-filled";
+import CustomerIcon from "~icons/carbon/friendship";
+import WarningIcon from "~icons/carbon/warning-alt-filled";
+import GenerateIcon from "~icons/carbon/chemistry";
+
+import { saveFile, selectLocalFiles, uploadFile } from "~/client/filesystem";
+import { resetInput, sleep } from "~/util";
+import { PositionsSettings } from "./Positions";
+import Modal, { ModalCloseButton } from "../Modal";
+import { createValidation } from "~/hooks/validation";
+import { MarkdownHelpLabel } from "../Markdown";
+
+const AccordionItemGrid: FlowComponent = (props) => {
+ return (
+
{props.children}
+ );
+};
+
+const AccordionItemEnd: Component = () => {
+ return ;
+};
+
+const AccordionItemDivider: FlowComponent = (props) => {
+ return {props.children}
;
+};
+
+const SettingsOverlay: Component = () => {
+ const [state, setState] = useContext(StoreContext)!;
+ const [localState, setLocalState] = useContext(LocalStoreContext)!;
+ const [loadModal, setLoadModal] = createStore({
+ open: false,
+ loading: false,
+ errors: null as null | {
+ message?: JSX.Element;
+ parseErrors: { path: string; message: string }[];
+ },
+ });
+ const [uiState, setUiState] = useContext(UiStoreContext)!;
+
+ const [AccordionItem] = createAccordion(null);
+
+ autoAnimate;
+
+ const [DocumentValidationContext, documentDataForm] = createValidation();
+ const [YourDataValidationContext, yourDataForm] = createValidation();
+ const [CustomerValidationContext, customerDataForm] = createValidation();
+
+ const AddressInputs: Component<{
+ namePrefix?: string;
+ nameRequired?: boolean;
+ setter: (name: string, value: any) => void;
+ address: () => AddressData;
+ }> = (props) => {
+ const isStructured = createMemo(() => isStructuredAddress(props.address()));
+ const withPrefix = (name: string) =>
+ createMemo(
+ () => `${props.namePrefix && props.namePrefix + "_"}${name}`
+ )();
+
+ return (
+ <>
+
+ props.setter("name", evt.currentTarget.value)}
+ />
+
+
+ props.setter("line1", evt.currentTarget.value)}
+ />
+ props.setter("line2", evt.currentTarget.value)}
+ />
+
+ props.setter(
+ "zip",
+ parseInt(evt.currentTarget.value) || undefined
+ )
+ }
+ />
+ props.setter("city", evt.currentTarget.value)}
+ />
+
+ >
+ );
+ };
+
+ const createCustomerAddressSetter = (alternative = false) => {
+ const addressField = alternative ? "alternativeAddress" : "debtorAddress";
+
+ return (name: any, value: any) => {
+ setState("customer", addressField, name, value);
+ };
+ };
+
+ const contactSetter = (name: any, value: any) => {
+ setLocalState("contact", name, value);
+ };
+
+ const fullWidthLabelWidth = "50%";
+ const FullWidthAccordionInput: Component[0]> = (
+ props
+ ) => (
+
+
+
+ );
+
+ const saveProject = () => {
+ const fileContent = JSON.stringify(
+ {
+ state: unwrap(state),
+ localState: unwrap(localState),
+ },
+ null,
+ " "
+ );
+
+ saveFile(
+ `rappli-${
+ state.project.projectNumber.length
+ ? state.project.projectNumber.replaceAll(" ", "-") + "-"
+ : ""
+ }${format(fromUnixTime(state.project.date), "yyyy-MM-dd")}.json`,
+ "application/json",
+ fileContent
+ );
+ };
+
+ const saveOnCtrlS = (e: KeyboardEvent) => {
+ if (e.ctrlKey && e.key === "s") {
+ e.preventDefault();
+ saveProject();
+ }
+ };
+
+ onMount(function () {
+ document.addEventListener("keydown", saveOnCtrlS);
+ });
+
+ onCleanup(function () {
+ document.removeEventListener("keydown", saveOnCtrlS);
+ });
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ setLoadModal("open", false);
+ }}
+ />
+
+
+
+
+
+
+
+ Dokument konnte nicht geladen werden
+
+
+
+
+ {loadModal.errors?.message}
+
+
+
+
+
+
+
+ |
+ JSON-Pfad |
+ Fehler |
+
+
+
+
+ {(error, idx) => (
+
+ {idx() + 1} |
+ {error.path} |
+ {error.message} |
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default SettingsOverlay;