feat: ability to rename fits and save them in the browser (#49)

This commit is contained in:
Patric Stout
2023-12-22 16:18:34 +01:00
committed by GitHub
parent 4c7be2a79c
commit f79e44ec4e
12 changed files with 416 additions and 7 deletions

View File

@@ -0,0 +1,33 @@
.modalDialog {
bottom: 0px;
background-color: rgba(200, 200, 200, 0.3);
left: 0px;
margin: 0 auto;
position: absolute;
right: 0px;
text-align: center;
top: 0px;
z-index: 100;
}
.modalDialog:before {
content: "";
display: inline-block;
height: 100%;
vertical-align: middle;
}
.content {
background-color: #111111;
border: 1px solid #303030;
border-radius: 7px;
color: #c5c5c5;
display: inline-block;
padding: 10px;
text-align: left;
vertical-align: middle;
}
.header {
font-size: 24px;
margin-bottom: 10px;
}

View File

@@ -0,0 +1,41 @@
import type { Meta, StoryObj } from '@storybook/react';
import React from "react";
import { ModalDialog } from './';
import { ModalDialogAnchor } from './ModalDialog';
const meta: Meta<typeof ModalDialog> = {
component: ModalDialog,
tags: ['autodocs'],
title: 'Component/ModalDialog',
};
export default meta;
type Story = StoryObj<typeof ModalDialog>;
const TestModalDialog = () => {
const [isOpen, setIsOpen] = React.useState(false);
return <>
<input type="button" value="Open" onClick={() => setIsOpen(true)} />
<ModalDialog visible={isOpen} onClose={() => setIsOpen(false)} title="Test Dialog">
Test
</ModalDialog>
</>;
}
export const Default: Story = {
args: {
},
render: () => (
<div>
<div>
Header not covered by modal dialog
</div>
<div style={{position: "relative", height: "40px"}}>
<ModalDialogAnchor />
<TestModalDialog />
</div>
</div>
),
};

View File

@@ -0,0 +1,57 @@
import clsx from "clsx";
import React, { useLayoutEffect } from "react";
import { createPortal } from "react-dom";
import styles from "./ModalDialog.module.css";
export interface ModalDialogProps {
/** Children that build up the modal dialog. */
children: React.ReactNode;
/** Classname to add to the content of the dialog. */
className?: string;
/** Whether the dialog should be visible. */
visible: boolean;
/** Callback called when the dialog should be closed. */
onClose: () => void;
/** Title of the modal dialog. */
title: string;
}
/**
* Create a modal dialog on top of all content.
*
* You need to set an <ModalDialogAnchor /> somewhere in the DOM for this to work.
*/
export const ModalDialog = (props: ModalDialogProps) => {
const [modalDialogAnchor, setModalDialogAnchor] = React.useState<HTMLElement | null>(null);
useLayoutEffect(() => {
if (modalDialogAnchor !== null) return;
const newModalDialogAnchor = document.getElementById("modalDialogAnchor");
if (newModalDialogAnchor === null) return;
setModalDialogAnchor(newModalDialogAnchor);
}, [modalDialogAnchor]);
if (!props.visible) return null;
if (modalDialogAnchor === null) return null;
return createPortal(<div className={styles.modalDialog} onClick={() => props.onClose()}>
<div className={clsx(styles.content, props.className)} onClick={(e) => e.stopPropagation()}>
<div className={styles.header}>{props.title}</div>
{props.children}
</div>
</div>, modalDialogAnchor);
};
/**
* Anchor for where the Modal Dialogs should be inserted in the DOM.
*
* This should be in a <div> which has a position and dimensions set. The modal
* will always use the full size of this <div> when rendering its content.
*/
export const ModalDialogAnchor = () => {
return <div id="modalDialogAnchor">
</div>
}

1
src/ModalDialog/index.ts Normal file
View File

@@ -0,0 +1 @@
export { ModalDialog, ModalDialogAnchor } from "./ModalDialog";